1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* @copyright Copyright (c) Flipbox Digital Limited |
5
|
|
|
*/ |
6
|
|
|
|
7
|
|
|
namespace flipbox\saml\sp\services\login; |
8
|
|
|
|
9
|
|
|
use craft\elements\User as UserElement; |
10
|
|
|
use craft\helpers\StringHelper; |
11
|
|
|
use craft\models\UserGroup; |
12
|
|
|
use flipbox\saml\sp\Saml; |
13
|
|
|
use SAML2\Assertion; |
14
|
|
|
use SAML2\Response; |
15
|
|
|
use yii\base\UserException; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Class UserGroups |
19
|
|
|
* @package flipbox\saml\sp\services |
20
|
|
|
*/ |
21
|
|
|
class UserGroups |
22
|
|
|
{ |
23
|
|
|
use AssertionTrait; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* @param string $groupName |
27
|
|
|
* @return UserGroup |
28
|
|
|
* @throws UserException |
29
|
|
|
* @throws \craft\errors\WrongEditionException |
30
|
|
|
*/ |
31
|
|
|
protected function findOrCreate($groupName): UserGroup |
32
|
|
|
{ |
33
|
|
|
|
34
|
|
|
$groupHandle = StringHelper::camelCase($groupName); |
35
|
|
|
|
36
|
|
|
if (! $userGroup = \Craft::$app->getUserGroups()->getGroupByHandle($groupHandle)) { |
37
|
|
|
if (! \Craft::$app->getUserGroups()->saveGroup( |
38
|
|
|
$userGroup = new UserGroup( |
39
|
|
|
[ |
40
|
|
|
'name' => $groupName, |
41
|
|
|
'handle' => $groupHandle, |
42
|
|
|
] |
43
|
|
|
) |
44
|
|
|
) |
45
|
|
|
) { |
46
|
|
|
throw new UserException("Error saving new group {$groupHandle}"); |
47
|
|
|
} |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
return $userGroup; |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* @param UserElement $user |
55
|
|
|
* @param Response $response |
56
|
|
|
* @return bool |
57
|
|
|
* @throws UserException |
58
|
|
|
* @throws \craft\errors\WrongEditionException |
59
|
|
|
*/ |
60
|
|
|
public function sync(UserElement $user, Response $response) |
61
|
|
|
{ |
62
|
|
|
foreach ($this->getAssertions($response) as $assertion) { |
63
|
|
|
$this->syncByAssertion($user, $assertion); |
|
|
|
|
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
return true; |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* @param UserElement $user |
71
|
|
|
* @param Assertion $assertion |
72
|
|
|
* @return bool |
73
|
|
|
* @deprecated Use sync. Will remove 2.1 |
74
|
|
|
* @throws UserException |
75
|
|
|
* @throws \craft\errors\WrongEditionException |
76
|
|
|
*/ |
77
|
|
|
public function syncByAssertion(UserElement $user, Assertion $assertion) |
78
|
|
|
{ |
79
|
|
|
/** |
80
|
|
|
* Nothing to do, move on |
81
|
|
|
*/ |
82
|
|
|
if (false === Saml::getInstance()->getSettings()->syncGroups) { |
83
|
|
|
return true; |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
$groupNames = Saml::getInstance()->getSettings()->groupAttributeNames; |
87
|
|
|
$groups = []; |
88
|
|
|
/** |
89
|
|
|
* Make sure there is an attribute statement |
90
|
|
|
*/ |
91
|
|
|
if (! $assertion->getAttributes()) { |
92
|
|
|
Saml::debug( |
93
|
|
|
'No attribute statement found, moving on.' |
94
|
|
|
); |
95
|
|
|
return true; |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
foreach ($assertion->getAttributes() as $attributeName => $attributeValue) { |
99
|
|
|
Saml::debug( |
100
|
|
|
sprintf( |
101
|
|
|
'Is attribute group? "%s" in %s', |
102
|
|
|
$attributeName, |
103
|
|
|
json_encode($groupNames) |
104
|
|
|
) |
105
|
|
|
); |
106
|
|
|
/** |
107
|
|
|
* Is there a group name match? |
108
|
|
|
* Match the attribute name to the specified name in the plugin settings |
109
|
|
|
*/ |
110
|
|
|
if (in_array($attributeName, $groupNames)) { |
111
|
|
|
/** |
112
|
|
|
* Loop thru all of the attributes values because they could have multiple values. |
113
|
|
|
* Example XML: |
114
|
|
|
* <saml2:Attribute Name="groups" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> |
115
|
|
|
* <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" |
116
|
|
|
* xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string"> |
117
|
|
|
* craft_admin |
118
|
|
|
* </saml2:AttributeValue> |
119
|
|
|
* <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" |
120
|
|
|
* xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string"> |
121
|
|
|
* craft_member |
122
|
|
|
* </saml2:AttributeValue> |
123
|
|
|
* </saml2:Attribute> |
124
|
|
|
*/ |
125
|
|
|
if (! is_array($attributeValue)) { |
126
|
|
|
$attributeValue = [$attributeValue]; |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
foreach ($attributeValue as $values) { |
130
|
|
|
if ($group = $this->findOrCreate($values)) { |
131
|
|
|
Saml::debug( |
132
|
|
|
sprintf( |
133
|
|
|
'Assigning group: %s', |
134
|
|
|
$group->name |
135
|
|
|
) |
136
|
|
|
); |
137
|
|
|
$groups[] = $group->id; |
138
|
|
|
} |
139
|
|
|
} |
140
|
|
|
} |
141
|
|
|
} |
142
|
|
|
/** |
143
|
|
|
* just return if this is empty |
144
|
|
|
*/ |
145
|
|
|
if (empty($groups)) { |
146
|
|
|
return true; |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* Get existing groups |
151
|
|
|
*/ |
152
|
|
|
$existingGroupIds = array_map( |
153
|
|
|
function ($group) { |
154
|
|
|
return (int)$group->id; |
155
|
|
|
}, |
156
|
|
|
$user->getGroups() |
157
|
|
|
); |
158
|
|
|
|
159
|
|
|
return \Craft::$app->getUsers()->assignUserToGroups( |
160
|
|
|
$user->id, |
161
|
|
|
array_unique( |
162
|
|
|
array_merge( |
163
|
|
|
$existingGroupIds, |
164
|
|
|
$groups |
165
|
|
|
) |
166
|
|
|
) |
167
|
|
|
); |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* @param UserElement $user |
172
|
|
|
* @return bool|null |
173
|
|
|
*/ |
174
|
|
|
public function assignDefaultGroups(\craft\elements\User $user) |
175
|
|
|
{ |
176
|
|
|
$groups = array_merge( |
177
|
|
|
$user->getGroups(), |
178
|
|
|
$newGroups = $this->getDefaultGroups() |
179
|
|
|
); |
180
|
|
|
|
181
|
|
|
/** |
182
|
|
|
* if it's not empty add the groups |
183
|
|
|
*/ |
184
|
|
|
if (! empty($newGroups)) { |
185
|
|
|
$groupIds = array_map( |
186
|
|
|
function ($group) { |
187
|
|
|
return (int)$group->id; |
188
|
|
|
}, |
189
|
|
|
$groups |
190
|
|
|
); |
191
|
|
|
|
192
|
|
|
if (\Craft::$app->getUsers()->assignUserToGroups($user->id, array_unique($groupIds))) { |
193
|
|
|
$user->setGroups($groups); |
194
|
|
|
} |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
return null; |
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
/** |
201
|
|
|
* @return array |
202
|
|
|
*/ |
203
|
|
|
public function getDefaultGroups() |
204
|
|
|
{ |
205
|
|
|
$groups = []; |
206
|
|
|
foreach (Saml::getInstance()->getSettings()->defaultGroupAssignments as $groupId) { |
207
|
|
|
$groups[$groupId] = \Craft::$app->getUserGroups()->getGroupById($groupId); |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
return $groups; |
211
|
|
|
} |
212
|
|
|
} |
213
|
|
|
|
This method has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.