AdUserProvider::__construct()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 11
rs 9.4285
cc 2
eloc 7
nc 2
nop 3
1
<?php
2
3
namespace Riper\Security\ActiveDirectoryBundle\Security\User;
4
5
use adLDAP\adLDAP;
6
use adLDAP\collections\adLDAPUserCollection;
7
use Riper\Security\ActiveDirectoryBundle\Exception\ADConnexionException;
8
use Symfony\Component\Security\Core\User\UserProviderInterface;
9
use Symfony\Component\Security\Core\User\UserInterface;
10
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
11
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
12
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
13
use Symfony\Component\Translation\TranslatorInterface;
14
use Riper\Security\ActiveDirectoryBundle\Service\AdldapService;
15
16
class AdUserProvider implements UserProviderInterface
17
{
18
    private $usernamePatterns = array();
19
    private $recursiveGrouproles = false;
20
21
    /**
22
     * @var TranslatorInterface
23
     */
24
    private $translator;
25
26
    private $config = array();
27
28
    public function __construct(array $config, AdldapService $AdldapService, TranslatorInterface $translator)
29
    {
30
        $this->config     = $config;
31
        $this->translator = $translator;
32
33
        $this->recursiveGrouproles = $this->getConfig('recursive_grouproles', false);
34
        $username_patterns         = $this->getConfig('username_patterns', array());
35
        foreach ($username_patterns as $pat) {
36
            array_push($this->usernamePatterns, $pat);
37
        }
38
    }
39
40
    /**
41
     * Retrieves a configuration value. make all required test.
42
     *
43
     * @param string $name Key name
44
     * @param mixed $default Default value
45
     *
46
     * @return mixed
47
     */
48
    protected function getConfig($name, $default)
49
    {
50
        if (!isset($this->config[$name])) {
51
            $return = $default;
52
        } else {
53
            $return = $this->config[$name];
54
        }
55
56
        return $return;
57
    }
58
59
    /**
60
     * Loads the user for the given username.
61
     *
62
     * This method must throw UsernameNotFoundException if the user is not
63
     * found.
64
     *
65
     * @param string $username The username
66
     *
67
     * @return AdUser
68
     *
69
     * @see UsernameNotFoundException
70
     *
71
     * @throws UsernameNotFoundException if the user is not found
72
     *
73
     */
74
    public function loadUserByUsername($username)
75
    {
76
        // The password is set to something impossible to find.
77
        try {
78
            $userString = $this->getUsernameFromString($username);
79
            $user = new AdUser(
80
                $this->getUsernameFromString($userString),
81
                uniqid(true) . rand(0, 424242),
82
                array()
83
            );
84
        } catch (\InvalidArgumentException $e) {
85
            $msg = $this->translator->trans(
86
                'riper.security.active_directory.invalid_user',
87
                array('%reason%' => $e->getMessage())
88
            );
89
            throw new UsernameNotFoundException($msg);
90
        }
91
92
        return $user;
93
    }
94
95
96
    /**
97
     * Retrieves the username from the login name, it is transformed using the username patterns.
98
     *
99
     * @param string $string
100
     *
101
     * @return string
102
     *
103
     * @throws \InvalidArgumentException
104
     */
105
    public function getUsernameFromString($string)
106
    {
107
        $username = $string;
108
        foreach ($this->usernamePatterns as $pattern) {
109
            if ($username == $string && preg_match($pattern, $string, $results)) {
110
                $username = $results[1];
111
                break;
112
            }
113
        }
114
        $username = strtolower($username);
115
        $pattern   = $this->getConfig('username_validation_pattern', '/^[a-z0-9-.]+$/i');
116
        if (preg_match($pattern, $username)) {
117
            return $username;
118
        }
119
120
        $msg = $this->translator->trans(
121
            'riper.security.active_directory.username_not_matching_rules',
122
            array(
123
                '%username%' => $username
124
            )
125
        );
126
        throw new \InvalidArgumentException($msg);
127
    }
128
129
    /**
130
     * Refreshes the user for the account interface.
131
     *
132
     * It is up to the implementation to decide if the user data should be
133
     * totally reloaded (e.g. from the database), or if the UserInterface
134
     * object can just be merged into some internal array of users / identity
135
     * map.
136
     *
137
     * @param UserInterface $user
138
     *
139
     * @return UserInterface
140
     *
141
     * @throws UnsupportedUserException if the account is not supported
142
     */
143
    public function refreshUser(UserInterface $user)
144
    {
145
        if (!$user instanceof AdUser) {
146
            $msg = $this->translator->trans(
147
                'riper.security.active_directory.bad_instance',
148
                array(
149
                    '%class_name%' => get_class($user)
150
                )
151
            );
152
            throw new UnsupportedUserException($msg);
153
        }
154
155
        return $user;
156
    }
157
158
    /**
159
     * Fetches the user data via adLDAP and stores it in the provided $adUser.
160
     *
161
     * @param AdUser $adUser
162
     * @param TokenInterface $token
163
     * @param adLDAP $adLdap
164
     */
165
    public function fetchData(AdUser $adUser, TokenInterface $token, adLDAP $adLdap)
166
    {
167
        $connected = $adLdap->connect();
168
        $isAD      = $adLdap->authenticate($adUser->getUsername(), $token->getCredentials());
169
        if (!$isAD || !$connected) {
170
            $msg = $this->translator->trans(
171
                'riper.security.active_directory.ad.bad_response',
172
                array(
173
                    '%connection_status%' => var_export($connected, 1),
174
                    '%is_AD%'             => var_export($isAD, 1),
175
                )
176
            );
177
            throw new ADConnexionException(
178
                $msg
179
            );
180
        }
181
        /** @var adLDAPUserCollection $user */
182
        $user = $adLdap->user()->infoCollection($adUser->getUsername());
183
184
        if ($user) {
185
            $groups = $adLdap->user()->groups($adUser->getUsername(), $this->recursiveGrouproles);
186
            /** End Fetching */
187
            $sfRoles = array();
188
            $sfRolesTemp = array();
189
            foreach ($groups as $r) {
190
                if (in_array($r, $sfRolesTemp) === false) {
191
                    $sfRoles[] = 'ROLE_' . strtoupper(str_replace(' ', '_', $r));
192
                    $sfRolesTemp[] = $r;
193
                }
194
            }
195
            $adUser->setRoles($sfRoles);
196
            unset($sfRolesTemp);
197
198
            $adUser->setDisplayName($user->displayName);
199
            $adUser->setEmail($user->mail);
200
201
            return true;
202
        }
203
    }
204
205
    /**
206
     * Whether this provider supports the given user class
207
     *
208
     * @param string $class
209
     *
210
     * @return Boolean
211
     */
212
    public function supportsClass($class)
213
    {
214
        return $class === 'Riper\Security\ActiveDirectoryBundle\Security\User\AdUser';
215
    }
216
}
217