Completed
Branch master (22f1c1)
by Damien
04:52
created

UserGroups::assignDefaultGroups()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 25
c 0
b 0
f 0
ccs 0
cts 13
cp 0
rs 9.52
cc 3
nc 3
nop 1
crap 12
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 LightSaml\Model\Assertion\Assertion;
14
use yii\base\UserException;
15
16
/**
17
 * Class UserGroups
18
 * @package flipbox\saml\sp\services
19
 */
20
class UserGroups
21
{
22
    /**
23
     * @param string $groupName
24
     * @return UserGroup
25
     * @throws UserException
26
     * @throws \craft\errors\WrongEditionException
27
     */
28
    protected function findOrCreate($groupName): UserGroup
29
    {
30
31
        $groupHandle = StringHelper::camelCase($groupName);
32
33
        if (! $userGroup = \Craft::$app->getUserGroups()->getGroupByHandle($groupHandle)) {
34
            if (! \Craft::$app->getUserGroups()->saveGroup(
35
                $userGroup = new UserGroup(
36
                    [
37
                        'name'   => $groupName,
38
                        'handle' => $groupHandle,
39
                    ]
40
                )
41
            )
42
            ) {
43
                throw new UserException("Error saving new group {$groupHandle}");
44
            }
45
        }
46
47
        return $userGroup;
48
    }
49
50
51
    /**
52
     * @param UserElement $user
53
     * @param Assertion $assertion
54
     * @return bool
55
     * @throws UserException
56
     * @throws \craft\errors\WrongEditionException
57
     */
58
    public function syncByAssertion(UserElement $user, Assertion $assertion)
59
    {
60
        /**
61
         * Nothing to do, move on
62
         */
63
        if (false === Saml::getInstance()->getSettings()->syncGroups) {
64
            return true;
65
        }
66
67
        $groupNames = Saml::getInstance()->getSettings()->groupAttributeNames;
68
        $groups = [];
69
        /**
70
         * Make sure there is an attribute statement
71
         */
72
        if (! $assertion->getFirstAttributeStatement()) {
73
            Saml::debug(
74
                'No attribute statement found, moving on.'
75
            );
76
            return true;
77
        }
78
79
        foreach ($assertion->getFirstAttributeStatement()->getAllAttributes() as $attribute) {
80
            Saml::debug(
81
                sprintf(
82
                    'Is attribute group? "%s" in %s',
83
                    $attribute->getName(),
84
                    json_encode($groupNames)
85
                )
86
            );
87
            /**
88
             * Is there a group name match?
89
             * Match the attribute name to the specified name in the plugin settings
90
             */
91
            if (in_array($attribute->getName(), $groupNames)) {
92
                /**
93
                 * Loop thru all of the attributes values because they could have multiple values.
94
                 * Example XML:
95
                 * <saml2:Attribute Name="groups" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
96
                 *   <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
97
                 *           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">
98
                 *           craft_admin
99
                 *           </saml2:AttributeValue>
100
                 *   <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
101
                 *           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">
102
                 *           craft_member
103
                 *           </saml2:AttributeValue>
104
                 * </saml2:Attribute>
105
                 */
106
                foreach ($attribute->getAllAttributeValues() as $value) {
107
                    if ($group = $this->findOrCreate($value)) {
108
                        Saml::debug(
109
                            sprintf(
110
                                'Assigning group: %s',
111
                                $group->name
112
                            )
113
                        );
114
                        $groups[] = $group->id;
115
                    }
116
                }
117
            }
118
        }
119
        /**
120
         * just return if this is empty
121
         */
122
        if (empty($groups)) {
123
            return true;
124
        }
125
126
        return \Craft::$app->getUsers()->assignUserToGroups($user->id, $groups);
127
    }
128
129
    /**
130
     * @param UserElement $user
131
     * @return bool|null
132
     */
133
    public function assignDefaultGroups(\craft\elements\User $user)
134
    {
135
        $groups = array_merge(
136
            $user->getGroups(),
137
            $newGroups = $this->getDefaultGroups()
138
        );
139
140
        /**
141
         * if it's not empty add the groups
142
         */
143
        if (! empty($newGroups)) {
144
            $groupIds = array_map(
145
                function ($group) {
146
                    return (int)$group->id;
147
                },
148
                $groups
149
            );
150
151
            if (\Craft::$app->getUsers()->assignUserToGroups($user->id, $groupIds)) {
152
                $user->setGroups($groups);
153
            }
154
        }
155
156
        return null;
157
    }
158
159
    /**
160
     * @return array
161
     */
162
    public function getDefaultGroups()
163
    {
164
        $groups = [];
165
        foreach (Saml::getInstance()->getSettings()->defaultGroupAssignments as $groupId) {
166
            $groups[$groupId] = \Craft::$app->getUserGroups()->getGroupById($groupId);
167
        }
168
169
        return $groups;
170
    }
171
}
172