Completed
Push — master ( 7401b1...7c15e2 )
by Damien
09:56
created

UserGroups   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 192
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 19
lcom 1
cbo 8
dl 0
loc 192
ccs 0
cts 69
cp 0
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A findOrCreate() 0 21 3
A sync() 0 8 2
C syncByAssertion() 0 92 9
A assignDefaultGroups() 0 25 3
A getDefaultGroups() 0 9 2
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);
0 ignored issues
show
Deprecated Code introduced by
The method flipbox\saml\sp\services...oups::syncByAssertion() has been deprecated with message: Use sync. Will remove 2.1

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.

Loading history...
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