Completed
Push — master ( 87925f...2aa9fa )
by Damien
06:56
created

UserGroups::find()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 16
ccs 0
cts 8
cp 0
rs 9.7333
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 6
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\models\Settings;
13
use flipbox\saml\sp\records\ProviderRecord;
14
use flipbox\saml\sp\Saml;
15
use SAML2\Assertion;
16
use SAML2\Response;
17
use yii\base\UserException;
18
19
/**
20
 * Class UserGroups
21
 * @package flipbox\saml\sp\services
22
 */
23
class UserGroups
24
{
25
    use AssertionTrait;
26
27
    /**
28
     * @param string $groupName
29
     * @return UserGroup|null
30
     * @throws UserException
31
     * @throws \craft\errors\WrongEditionException
32
     */
33
    protected function find($groupName)
34
    {
35
36
        $groupHandle = StringHelper::camelCase($groupName);
37
38
        if (! $userGroup = \Craft::$app->getUserGroups()->getGroupByHandle($groupHandle)) {
39
            Saml::warning(
40
                sprintf(
41
                    "Group handle %s not found. This group must be created by an admin users before user can be assigned to it.",
42
                    $groupHandle
43
                )
44
            );
45
        }
46
47
        return $userGroup;
48
    }
49
50
    /**
51
     * @param UserElement $user
52
     * @param Response $response
53
     * @return bool
54
     * @throws UserException
55
     * @throws \craft\errors\WrongEditionException
56
     */
57
    public function sync(UserElement $user, Response $response, ProviderRecord $serviceProvider, Settings $settings)
58
    {
59
        foreach ($this->getAssertions($response, $serviceProvider) as $assertion) {
60
            $this->syncByAssertion(
61
                $user,
62
                $assertion,
63
                $settings
64
            );
65
        }
66
67
        $this->assignDefaultGroups(
68
            $user,
69
            $settings
70
        );
71
72
        return true;
73
    }
74
75
    /**
76
     * @param UserElement $user
77
     * @param Assertion $assertion
78
     * @return bool
79
     * @throws UserException
80
     * @throws \craft\errors\WrongEditionException
81
     */
82
    protected function syncByAssertion(
83
        UserElement $user,
84
        Assertion $assertion,
85
        Settings $settings
86
    ) {
87
        /**
88
         * Nothing to do, move on
89
         */
90
        if (false === $settings->syncGroups) {
91
            return true;
92
        }
93
94
        $groupNames = $settings->groupAttributeNames;
95
        $groups = [];
96
        /**
97
         * Make sure there is an attribute statement
98
         */
99
        if (! $assertion->getAttributes()) {
100
            Saml::debug(
101
                'No attribute statement found, moving on.'
102
            );
103
            return true;
104
        }
105
106
        foreach ($assertion->getAttributes() as $attributeName => $attributeValue) {
107
            Saml::debug(
108
                sprintf(
109
                    'Is attribute group? "%s" in %s',
110
                    $attributeName,
111
                    json_encode($groupNames)
112
                )
113
            );
114
            /**
115
             * Is there a group name match?
116
             * Match the attribute name to the specified name in the plugin settings
117
             */
118
            if (in_array($attributeName, $groupNames)) {
119
                /**
120
                 * Loop thru all of the attributes values because they could have multiple values.
121
                 * Example XML:
122
                 * <saml2:Attribute Name="groups" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
123
                 *   <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
124
                 *           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">
125
                 *           craft_admin
126
                 *           </saml2:AttributeValue>
127
                 *   <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
128
                 *           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">
129
                 *           craft_member
130
                 *           </saml2:AttributeValue>
131
                 * </saml2:Attribute>
132
                 */
133
                if (! is_array($attributeValue)) {
134
                    $attributeValue = [$attributeValue];
135
                }
136
137
                foreach ($attributeValue as $groupName) {
138
                    if ($group = $this->find($groupName)) {
139
                        Saml::debug(
140
                            sprintf(
141
                                'Assigning group: %s',
142
                                $group->name
143
                            )
144
                        );
145
                        $groups[] = $group->id;
146
                    } else {
147
                        Saml::debug(
148
                            sprintf(
149
                                'Group not found: %s',
150
                                $groupName
151
                            )
152
                        );
153
                    }
154
                }
155
            }
156
        }
157
        /**
158
         * just return if this is empty
159
         */
160
        if (empty($groups)) {
161
            return true;
162
        }
163
164
        /**
165
         * Get existing groups
166
         */
167
        $existingGroupIds = array_map(
168
            function ($group) {
169
                return (int)$group->id;
170
            },
171
            $user->getGroups()
172
        );
173
174
        return \Craft::$app->getUsers()->assignUserToGroups(
175
            $user->id,
176
            array_unique(
177
                array_merge(
178
                    $existingGroupIds,
179
                    $groups
180
                )
181
            )
182
        );
183
    }
184
185
    /**
186
     * @param UserElement $user
187
     * @return bool|null
188
     */
189
    protected function assignDefaultGroups(\craft\elements\User $user, Settings $settings)
0 ignored issues
show
Unused Code introduced by
The parameter $settings is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
190
    {
191
        $groups = array_merge(
192
            $user->getGroups(),
193
            $newGroups = $this->getDefaultGroups()
194
        );
195
196
        /**
197
         * if it's not empty add the groups
198
         */
199
        if (! empty($newGroups)) {
200
            $groupIds = array_map(
201
                function ($group) {
202
                    return (int)$group->id;
203
                },
204
                $groups
205
            );
206
207
            if (\Craft::$app->getUsers()->assignUserToGroups($user->id, array_unique($groupIds))) {
208
                $user->setGroups($groups);
209
            }
210
        }
211
212
        return null;
213
    }
214
215
    /**
216
     * @return array
217
     */
218
    protected function getDefaultGroups()
219
    {
220
        $groups = [];
221
        foreach (Saml::getInstance()->getSettings()->defaultGroupAssignments as $groupId) {
222
            $groups[$groupId] = \Craft::$app->getUserGroups()->getGroupById($groupId);
223
        }
224
225
        return $groups;
226
    }
227
}
228