Test Failed
Push — dependabot/composer/newinterna... ( de8420 )
by
unknown
13:57 queued 08:25
created
includes/Security/CredentialProviders/U2FCredentialProvider.php 1 patch
Indentation   +127 added lines, -127 removed lines patch added patch discarded remove patch
@@ -20,131 +20,131 @@
 block discarded – undo
20 20
 
21 21
 class U2FCredentialProvider extends CredentialProviderBase
22 22
 {
23
-    /** @var U2F */
24
-    private $u2f;
25
-
26
-    /**
27
-     * U2FCredentialProvider constructor.
28
-     *
29
-     * @param PdoDatabase       $database
30
-     * @param SiteConfiguration $configuration
31
-     */
32
-    public function __construct(PdoDatabase $database, SiteConfiguration $configuration)
33
-    {
34
-        parent::__construct($database, $configuration, 'u2f');
35
-
36
-        $appId = 'https://' . WebRequest::httpHost();
37
-        $this->u2f = new U2F($appId);
38
-    }
39
-
40
-    /**
41
-     * Validates a user-provided credential
42
-     *
43
-     * @param User   $user The user to test the authentication against
44
-     * @param string $data The raw credential data to be validated
45
-     *
46
-     * @return bool
47
-     * @throws OptimisticLockFailedException
48
-     */
49
-    public function authenticate(User $user, $data)
50
-    {
51
-        if (!is_array($data)) {
52
-            return false;
53
-        }
54
-
55
-        list($authenticate, $request, $isU2F) = $data;
56
-
57
-        if ($isU2F !== 'u2f') {
58
-            return false;
59
-        }
60
-
61
-        $storedData = $this->getCredentialData($user->getId(), false);
62
-        $registrations = json_decode($storedData->getData());
63
-
64
-        try {
65
-            $updatedRegistration = $this->u2f->doAuthenticate($request, array($registrations), $authenticate);
66
-            $storedData->setData(json_encode($updatedRegistration));
67
-            $storedData->save();
68
-        }
69
-        catch (Error $ex) {
70
-            return false;
71
-        }
72
-
73
-        return true;
74
-    }
75
-
76
-    public function enable(User $user, $request, $u2fData)
77
-    {
78
-        $registrationData = $this->u2f->doRegister($request, $u2fData);
79
-
80
-        $storedData = $this->getCredentialData($user->getId(), true);
81
-
82
-        if ($storedData === null) {
83
-            throw new ApplicationLogicException('Credential data not found');
84
-        }
85
-
86
-        if ($storedData->getTimeout() > new DateTimeImmutable()) {
87
-            $storedData->setData(json_encode($registrationData));
88
-            $storedData->setDisabled(0);
89
-            $storedData->setTimeout(null);
90
-            $storedData->save();
91
-        }
92
-    }
93
-
94
-    /**
95
-     * @param User   $user   The user the credential belongs to
96
-     * @param int    $factor The factor this credential provides
97
-     * @param string $data   Unused here, due to multi-stage enrollment
98
-     */
99
-    public function setCredential(User $user, $factor, $data)
100
-    {
101
-        $storedData = $this->getCredentialData($user->getId(), null);
102
-
103
-        if ($storedData !== null) {
104
-            $storedData->delete();
105
-        }
106
-
107
-        $storedData = $this->createNewCredential($user);
108
-
109
-        $storedData->setData(null);
110
-        $storedData->setFactor($factor);
111
-        $storedData->setTimeout(new DateTimeImmutable('+ 1 hour'));
112
-        $storedData->setDisabled(1);
113
-        $storedData->setPriority(4);
114
-        $storedData->setVersion(1);
115
-
116
-        $storedData->save();
117
-    }
118
-
119
-    public function isPartiallyEnrolled(User $user)
120
-    {
121
-        $storedData = $this->getCredentialData($user->getId(), true);
122
-
123
-        if ($storedData->getTimeout() < new DateTimeImmutable()) {
124
-            $storedData->delete();
125
-
126
-            return false;
127
-        }
128
-
129
-        if ($storedData === null) {
130
-            return false;
131
-        }
132
-
133
-        return true;
134
-    }
135
-
136
-    public function getRegistrationData()
137
-    {
138
-        return $this->u2f->getRegisterData();
139
-    }
140
-
141
-    public function getAuthenticationData(User $user)
142
-    {
143
-        $storedData = $this->getCredentialData($user->getId(), false);
144
-        $registrations = json_decode($storedData->getData());
145
-
146
-        $authenticateData = $this->u2f->getAuthenticateData(array($registrations));
147
-
148
-        return $authenticateData;
149
-    }
23
+	/** @var U2F */
24
+	private $u2f;
25
+
26
+	/**
27
+	 * U2FCredentialProvider constructor.
28
+	 *
29
+	 * @param PdoDatabase       $database
30
+	 * @param SiteConfiguration $configuration
31
+	 */
32
+	public function __construct(PdoDatabase $database, SiteConfiguration $configuration)
33
+	{
34
+		parent::__construct($database, $configuration, 'u2f');
35
+
36
+		$appId = 'https://' . WebRequest::httpHost();
37
+		$this->u2f = new U2F($appId);
38
+	}
39
+
40
+	/**
41
+	 * Validates a user-provided credential
42
+	 *
43
+	 * @param User   $user The user to test the authentication against
44
+	 * @param string $data The raw credential data to be validated
45
+	 *
46
+	 * @return bool
47
+	 * @throws OptimisticLockFailedException
48
+	 */
49
+	public function authenticate(User $user, $data)
50
+	{
51
+		if (!is_array($data)) {
52
+			return false;
53
+		}
54
+
55
+		list($authenticate, $request, $isU2F) = $data;
56
+
57
+		if ($isU2F !== 'u2f') {
58
+			return false;
59
+		}
60
+
61
+		$storedData = $this->getCredentialData($user->getId(), false);
62
+		$registrations = json_decode($storedData->getData());
63
+
64
+		try {
65
+			$updatedRegistration = $this->u2f->doAuthenticate($request, array($registrations), $authenticate);
66
+			$storedData->setData(json_encode($updatedRegistration));
67
+			$storedData->save();
68
+		}
69
+		catch (Error $ex) {
70
+			return false;
71
+		}
72
+
73
+		return true;
74
+	}
75
+
76
+	public function enable(User $user, $request, $u2fData)
77
+	{
78
+		$registrationData = $this->u2f->doRegister($request, $u2fData);
79
+
80
+		$storedData = $this->getCredentialData($user->getId(), true);
81
+
82
+		if ($storedData === null) {
83
+			throw new ApplicationLogicException('Credential data not found');
84
+		}
85
+
86
+		if ($storedData->getTimeout() > new DateTimeImmutable()) {
87
+			$storedData->setData(json_encode($registrationData));
88
+			$storedData->setDisabled(0);
89
+			$storedData->setTimeout(null);
90
+			$storedData->save();
91
+		}
92
+	}
93
+
94
+	/**
95
+	 * @param User   $user   The user the credential belongs to
96
+	 * @param int    $factor The factor this credential provides
97
+	 * @param string $data   Unused here, due to multi-stage enrollment
98
+	 */
99
+	public function setCredential(User $user, $factor, $data)
100
+	{
101
+		$storedData = $this->getCredentialData($user->getId(), null);
102
+
103
+		if ($storedData !== null) {
104
+			$storedData->delete();
105
+		}
106
+
107
+		$storedData = $this->createNewCredential($user);
108
+
109
+		$storedData->setData(null);
110
+		$storedData->setFactor($factor);
111
+		$storedData->setTimeout(new DateTimeImmutable('+ 1 hour'));
112
+		$storedData->setDisabled(1);
113
+		$storedData->setPriority(4);
114
+		$storedData->setVersion(1);
115
+
116
+		$storedData->save();
117
+	}
118
+
119
+	public function isPartiallyEnrolled(User $user)
120
+	{
121
+		$storedData = $this->getCredentialData($user->getId(), true);
122
+
123
+		if ($storedData->getTimeout() < new DateTimeImmutable()) {
124
+			$storedData->delete();
125
+
126
+			return false;
127
+		}
128
+
129
+		if ($storedData === null) {
130
+			return false;
131
+		}
132
+
133
+		return true;
134
+	}
135
+
136
+	public function getRegistrationData()
137
+	{
138
+		return $this->u2f->getRegisterData();
139
+	}
140
+
141
+	public function getAuthenticationData(User $user)
142
+	{
143
+		$storedData = $this->getCredentialData($user->getId(), false);
144
+		$registrations = json_decode($storedData->getData());
145
+
146
+		$authenticateData = $this->u2f->getAuthenticateData(array($registrations));
147
+
148
+		return $authenticateData;
149
+	}
150 150
 }
Please login to merge, or discard this patch.
includes/Security/CredentialProviders/CredentialProviderBase.php 3 patches
Indentation   +133 added lines, -133 removed lines patch added patch discarded remove patch
@@ -15,137 +15,137 @@
 block discarded – undo
15 15
 
16 16
 abstract class CredentialProviderBase implements ICredentialProvider
17 17
 {
18
-    /**
19
-     * @var PdoDatabase
20
-     */
21
-    private $database;
22
-    /**
23
-     * @var SiteConfiguration
24
-     */
25
-    private $configuration;
26
-    /** @var string */
27
-    private $type;
28
-
29
-    /**
30
-     * CredentialProviderBase constructor.
31
-     *
32
-     * @param PdoDatabase       $database
33
-     * @param SiteConfiguration $configuration
34
-     * @param string            $type
35
-     */
36
-    public function __construct(PdoDatabase $database, SiteConfiguration $configuration, $type)
37
-    {
38
-        $this->database = $database;
39
-        $this->configuration = $configuration;
40
-        $this->type = $type;
41
-    }
42
-
43
-    /**
44
-     * @param int  $userId
45
-     *
46
-     * @param bool $disabled
47
-     *
48
-     * @return Credential
49
-     */
50
-    protected function getCredentialData($userId, $disabled = false)
51
-    {
52
-        $sql = 'SELECT * FROM credential WHERE type = :t AND user = :u';
53
-        $parameters = array(
54
-            ':u' => $userId,
55
-            ':t' => $this->type
56
-        );
57
-
58
-        if($disabled !== null) {
59
-            $sql .= ' AND disabled = :d';
60
-            $parameters[':d'] = $disabled ? 1 : 0;
61
-        }
62
-
63
-        $statement = $this->database->prepare($sql);
64
-        $statement->execute($parameters);
65
-
66
-        /** @var Credential $obj */
67
-        $obj = $statement->fetchObject(Credential::class);
68
-
69
-        if ($obj === false) {
70
-            return null;
71
-        }
72
-
73
-        $obj->setDatabase($this->database);
74
-
75
-        $statement->closeCursor();
76
-
77
-        return $obj;
78
-    }
79
-
80
-    /**
81
-     * @return PdoDatabase
82
-     */
83
-    public function getDatabase()
84
-    {
85
-        return $this->database;
86
-    }
87
-
88
-    /**
89
-     * @return SiteConfiguration
90
-     */
91
-    public function getConfiguration()
92
-    {
93
-        return $this->configuration;
94
-    }
95
-
96
-    public function deleteCredential(User $user) {
97
-        // get this factor
98
-        $statement = $this->database->prepare('SELECT * FROM credential WHERE user = :user AND type = :type');
99
-        $statement->execute(array(':user' => $user->getId(), ':type' => $this->type));
100
-        /** @var Credential $credential */
101
-        $credential = $statement->fetchObject(Credential::class);
102
-        $credential->setDatabase($this->database);
103
-        $statement->closeCursor();
104
-
105
-        $stage = $credential->getFactor();
106
-
107
-        $statement = $this->database->prepare('SELECT COUNT(*) FROM credential WHERE user = :user AND factor = :factor');
108
-        $statement->execute(array(':user' => $user->getId(), ':factor' => $stage));
109
-        $alternates = $statement->fetchColumn();
110
-        $statement->closeCursor();
111
-
112
-        if($alternates <= 1) {
113
-            // decrement the factor for every stage above this
114
-            $sql = 'UPDATE credential SET factor = factor - 1 WHERE user = :user AND factor > :factor';
115
-            $statement = $this->database->prepare($sql);
116
-            $statement->execute(array(':user' => $user->getId(), ':factor' => $stage));
117
-        }
118
-        else {
119
-            // There are other auth factors at this point. Don't renumber the factors just yet.
120
-        }
121
-
122
-        // delete this credential.
123
-        $credential->delete();
124
-    }
125
-
126
-    /**
127
-     * @param User $user
128
-     *
129
-     * @return Credential
130
-     */
131
-    protected function createNewCredential(User $user)
132
-    {
133
-        $credential = new Credential();
134
-        $credential->setDatabase($this->getDatabase());
135
-        $credential->setUserId($user->getId());
136
-        $credential->setType($this->type);
137
-
138
-        return $credential;
139
-    }
140
-
141
-    /**
142
-     * @param int $userId
143
-     *
144
-     * @return bool
145
-     */
146
-    public function userIsEnrolled($userId) {
147
-        $cred = $this->getCredentialData($userId);
148
-
149
-        return $cred !== null;
150
-    }
18
+	/**
19
+	 * @var PdoDatabase
20
+	 */
21
+	private $database;
22
+	/**
23
+	 * @var SiteConfiguration
24
+	 */
25
+	private $configuration;
26
+	/** @var string */
27
+	private $type;
28
+
29
+	/**
30
+	 * CredentialProviderBase constructor.
31
+	 *
32
+	 * @param PdoDatabase       $database
33
+	 * @param SiteConfiguration $configuration
34
+	 * @param string            $type
35
+	 */
36
+	public function __construct(PdoDatabase $database, SiteConfiguration $configuration, $type)
37
+	{
38
+		$this->database = $database;
39
+		$this->configuration = $configuration;
40
+		$this->type = $type;
41
+	}
42
+
43
+	/**
44
+	 * @param int  $userId
45
+	 *
46
+	 * @param bool $disabled
47
+	 *
48
+	 * @return Credential
49
+	 */
50
+	protected function getCredentialData($userId, $disabled = false)
51
+	{
52
+		$sql = 'SELECT * FROM credential WHERE type = :t AND user = :u';
53
+		$parameters = array(
54
+			':u' => $userId,
55
+			':t' => $this->type
56
+		);
57
+
58
+		if($disabled !== null) {
59
+			$sql .= ' AND disabled = :d';
60
+			$parameters[':d'] = $disabled ? 1 : 0;
61
+		}
62
+
63
+		$statement = $this->database->prepare($sql);
64
+		$statement->execute($parameters);
65
+
66
+		/** @var Credential $obj */
67
+		$obj = $statement->fetchObject(Credential::class);
68
+
69
+		if ($obj === false) {
70
+			return null;
71
+		}
72
+
73
+		$obj->setDatabase($this->database);
74
+
75
+		$statement->closeCursor();
76
+
77
+		return $obj;
78
+	}
79
+
80
+	/**
81
+	 * @return PdoDatabase
82
+	 */
83
+	public function getDatabase()
84
+	{
85
+		return $this->database;
86
+	}
87
+
88
+	/**
89
+	 * @return SiteConfiguration
90
+	 */
91
+	public function getConfiguration()
92
+	{
93
+		return $this->configuration;
94
+	}
95
+
96
+	public function deleteCredential(User $user) {
97
+		// get this factor
98
+		$statement = $this->database->prepare('SELECT * FROM credential WHERE user = :user AND type = :type');
99
+		$statement->execute(array(':user' => $user->getId(), ':type' => $this->type));
100
+		/** @var Credential $credential */
101
+		$credential = $statement->fetchObject(Credential::class);
102
+		$credential->setDatabase($this->database);
103
+		$statement->closeCursor();
104
+
105
+		$stage = $credential->getFactor();
106
+
107
+		$statement = $this->database->prepare('SELECT COUNT(*) FROM credential WHERE user = :user AND factor = :factor');
108
+		$statement->execute(array(':user' => $user->getId(), ':factor' => $stage));
109
+		$alternates = $statement->fetchColumn();
110
+		$statement->closeCursor();
111
+
112
+		if($alternates <= 1) {
113
+			// decrement the factor for every stage above this
114
+			$sql = 'UPDATE credential SET factor = factor - 1 WHERE user = :user AND factor > :factor';
115
+			$statement = $this->database->prepare($sql);
116
+			$statement->execute(array(':user' => $user->getId(), ':factor' => $stage));
117
+		}
118
+		else {
119
+			// There are other auth factors at this point. Don't renumber the factors just yet.
120
+		}
121
+
122
+		// delete this credential.
123
+		$credential->delete();
124
+	}
125
+
126
+	/**
127
+	 * @param User $user
128
+	 *
129
+	 * @return Credential
130
+	 */
131
+	protected function createNewCredential(User $user)
132
+	{
133
+		$credential = new Credential();
134
+		$credential->setDatabase($this->getDatabase());
135
+		$credential->setUserId($user->getId());
136
+		$credential->setType($this->type);
137
+
138
+		return $credential;
139
+	}
140
+
141
+	/**
142
+	 * @param int $userId
143
+	 *
144
+	 * @return bool
145
+	 */
146
+	public function userIsEnrolled($userId) {
147
+		$cred = $this->getCredentialData($userId);
148
+
149
+		return $cred !== null;
150
+	}
151 151
 }
152 152
\ No newline at end of file
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -55,7 +55,7 @@  discard block
 block discarded – undo
55 55
             ':t' => $this->type
56 56
         );
57 57
 
58
-        if($disabled !== null) {
58
+        if ($disabled !== null) {
59 59
             $sql .= ' AND disabled = :d';
60 60
             $parameters[':d'] = $disabled ? 1 : 0;
61 61
         }
@@ -109,7 +109,7 @@  discard block
 block discarded – undo
109 109
         $alternates = $statement->fetchColumn();
110 110
         $statement->closeCursor();
111 111
 
112
-        if($alternates <= 1) {
112
+        if ($alternates <= 1) {
113 113
             // decrement the factor for every stage above this
114 114
             $sql = 'UPDATE credential SET factor = factor - 1 WHERE user = :user AND factor > :factor';
115 115
             $statement = $this->database->prepare($sql);
Please login to merge, or discard this patch.
Braces   +5 added lines, -4 removed lines patch added patch discarded remove patch
@@ -93,7 +93,8 @@  discard block
 block discarded – undo
93 93
         return $this->configuration;
94 94
     }
95 95
 
96
-    public function deleteCredential(User $user) {
96
+    public function deleteCredential(User $user)
97
+    {
97 98
         // get this factor
98 99
         $statement = $this->database->prepare('SELECT * FROM credential WHERE user = :user AND type = :type');
99 100
         $statement->execute(array(':user' => $user->getId(), ':type' => $this->type));
@@ -114,8 +115,7 @@  discard block
 block discarded – undo
114 115
             $sql = 'UPDATE credential SET factor = factor - 1 WHERE user = :user AND factor > :factor';
115 116
             $statement = $this->database->prepare($sql);
116 117
             $statement->execute(array(':user' => $user->getId(), ':factor' => $stage));
117
-        }
118
-        else {
118
+        } else {
119 119
             // There are other auth factors at this point. Don't renumber the factors just yet.
120 120
         }
121 121
 
@@ -143,7 +143,8 @@  discard block
 block discarded – undo
143 143
      *
144 144
      * @return bool
145 145
      */
146
-    public function userIsEnrolled($userId) {
146
+    public function userIsEnrolled($userId)
147
+    {
147 148
         $cred = $this->getCredentialData($userId);
148 149
 
149 150
         return $cred !== null;
Please login to merge, or discard this patch.
includes/Security/CredentialProviders/TotpCredentialProvider.php 1 patch
Indentation   +130 added lines, -130 removed lines patch added patch discarded remove patch
@@ -19,137 +19,137 @@
 block discarded – undo
19 19
 
20 20
 class TotpCredentialProvider extends CredentialProviderBase
21 21
 {
22
-    /** @var EncryptionHelper */
23
-    private $encryptionHelper;
24
-
25
-    /**
26
-     * TotpCredentialProvider constructor.
27
-     *
28
-     * @param PdoDatabase       $database
29
-     * @param SiteConfiguration $configuration
30
-     */
31
-    public function __construct(PdoDatabase $database, SiteConfiguration $configuration)
32
-    {
33
-        parent::__construct($database, $configuration, 'totp');
34
-        $this->encryptionHelper = new EncryptionHelper($configuration);
35
-    }
36
-
37
-    /**
38
-     * Validates a user-provided credential
39
-     *
40
-     * @param User   $user The user to test the authentication against
41
-     * @param string $data The raw credential data to be validated
42
-     *
43
-     * @return bool
44
-     * @throws ApplicationLogicException
45
-     */
46
-    public function authenticate(User $user, $data)
47
-    {
48
-        if (is_array($data)) {
49
-            return false;
50
-        }
51
-
52
-        $storedData = $this->getCredentialData($user->getId());
53
-
54
-        if ($storedData === null) {
55
-            throw new ApplicationLogicException('Credential data not found');
56
-        }
57
-
58
-        $provisioningUrl = $this->encryptionHelper->decryptData($storedData->getData());
59
-        $totp = Factory::loadFromProvisioningUri($provisioningUrl);
60
-
61
-        return $totp->verify($data, null, 2);
62
-    }
63
-
64
-    public function verifyEnable(User $user, $data)
65
-    {
66
-        $storedData = $this->getCredentialData($user->getId(), true);
67
-
68
-        if ($storedData === null) {
69
-            throw new ApplicationLogicException('Credential data not found');
70
-        }
71
-
72
-        $provisioningUrl = $this->encryptionHelper->decryptData($storedData->getData());
73
-        $totp = Factory::loadFromProvisioningUri($provisioningUrl);
74
-
75
-        $result = $totp->verify($data, null, 2);
76
-
77
-        if ($result && $storedData->getTimeout() > new DateTimeImmutable()) {
78
-            $storedData->setDisabled(0);
79
-            $storedData->setPriority(5);
80
-            $storedData->setTimeout(null);
81
-            $storedData->save();
82
-        }
83
-
84
-        return $result;
85
-    }
86
-
87
-    /**
88
-     * @param User   $user   The user the credential belongs to
89
-     * @param int    $factor The factor this credential provides
90
-     * @param string $data   Unused here, due to there being no user-provided data. We provide the user with the secret.
91
-     */
92
-    public function setCredential(User $user, $factor, $data)
93
-    {
94
-        $issuer = 'ACC - ' . $this->getConfiguration()->getIrcNotificationsInstance();
95
-        $totp = TOTP::create();
96
-        $totp->setLabel($user->getUsername());
97
-        $totp->setIssuer($issuer);
98
-
99
-        $storedData = $this->getCredentialData($user->getId(), null);
100
-
101
-        if ($storedData !== null) {
102
-            $storedData->delete();
103
-        }
104
-
105
-        $storedData = $this->createNewCredential($user);
106
-
107
-        $storedData->setData($this->encryptionHelper->encryptData($totp->getProvisioningUri()));
108
-        $storedData->setFactor($factor);
109
-        $storedData->setTimeout(new DateTimeImmutable('+ 1 hour'));
110
-        $storedData->setDisabled(1);
111
-        $storedData->setVersion(1);
112
-
113
-        $storedData->save();
114
-    }
115
-
116
-    public function getProvisioningUrl(User $user)
117
-    {
118
-        $storedData = $this->getCredentialData($user->getId(), true);
119
-
120
-        if ($storedData->getTimeout() < new DateTimeImmutable()) {
121
-            $storedData->delete();
122
-            $storedData = null;
123
-        }
124
-
125
-        if ($storedData === null) {
126
-            throw new ApplicationLogicException('Credential data not found');
127
-        }
128
-
129
-        return $this->encryptionHelper->decryptData($storedData->getData());
130
-    }
131
-
132
-    public function isPartiallyEnrolled(User $user)
133
-    {
134
-        $storedData = $this->getCredentialData($user->getId(), true);
135
-
136
-        if ($storedData->getTimeout() < new DateTimeImmutable()) {
137
-            $storedData->delete();
138
-
139
-            return false;
140
-        }
141
-
142
-        if ($storedData === null) {
143
-            return false;
144
-        }
22
+	/** @var EncryptionHelper */
23
+	private $encryptionHelper;
24
+
25
+	/**
26
+	 * TotpCredentialProvider constructor.
27
+	 *
28
+	 * @param PdoDatabase       $database
29
+	 * @param SiteConfiguration $configuration
30
+	 */
31
+	public function __construct(PdoDatabase $database, SiteConfiguration $configuration)
32
+	{
33
+		parent::__construct($database, $configuration, 'totp');
34
+		$this->encryptionHelper = new EncryptionHelper($configuration);
35
+	}
36
+
37
+	/**
38
+	 * Validates a user-provided credential
39
+	 *
40
+	 * @param User   $user The user to test the authentication against
41
+	 * @param string $data The raw credential data to be validated
42
+	 *
43
+	 * @return bool
44
+	 * @throws ApplicationLogicException
45
+	 */
46
+	public function authenticate(User $user, $data)
47
+	{
48
+		if (is_array($data)) {
49
+			return false;
50
+		}
51
+
52
+		$storedData = $this->getCredentialData($user->getId());
53
+
54
+		if ($storedData === null) {
55
+			throw new ApplicationLogicException('Credential data not found');
56
+		}
57
+
58
+		$provisioningUrl = $this->encryptionHelper->decryptData($storedData->getData());
59
+		$totp = Factory::loadFromProvisioningUri($provisioningUrl);
60
+
61
+		return $totp->verify($data, null, 2);
62
+	}
63
+
64
+	public function verifyEnable(User $user, $data)
65
+	{
66
+		$storedData = $this->getCredentialData($user->getId(), true);
67
+
68
+		if ($storedData === null) {
69
+			throw new ApplicationLogicException('Credential data not found');
70
+		}
71
+
72
+		$provisioningUrl = $this->encryptionHelper->decryptData($storedData->getData());
73
+		$totp = Factory::loadFromProvisioningUri($provisioningUrl);
74
+
75
+		$result = $totp->verify($data, null, 2);
76
+
77
+		if ($result && $storedData->getTimeout() > new DateTimeImmutable()) {
78
+			$storedData->setDisabled(0);
79
+			$storedData->setPriority(5);
80
+			$storedData->setTimeout(null);
81
+			$storedData->save();
82
+		}
83
+
84
+		return $result;
85
+	}
86
+
87
+	/**
88
+	 * @param User   $user   The user the credential belongs to
89
+	 * @param int    $factor The factor this credential provides
90
+	 * @param string $data   Unused here, due to there being no user-provided data. We provide the user with the secret.
91
+	 */
92
+	public function setCredential(User $user, $factor, $data)
93
+	{
94
+		$issuer = 'ACC - ' . $this->getConfiguration()->getIrcNotificationsInstance();
95
+		$totp = TOTP::create();
96
+		$totp->setLabel($user->getUsername());
97
+		$totp->setIssuer($issuer);
98
+
99
+		$storedData = $this->getCredentialData($user->getId(), null);
100
+
101
+		if ($storedData !== null) {
102
+			$storedData->delete();
103
+		}
104
+
105
+		$storedData = $this->createNewCredential($user);
106
+
107
+		$storedData->setData($this->encryptionHelper->encryptData($totp->getProvisioningUri()));
108
+		$storedData->setFactor($factor);
109
+		$storedData->setTimeout(new DateTimeImmutable('+ 1 hour'));
110
+		$storedData->setDisabled(1);
111
+		$storedData->setVersion(1);
112
+
113
+		$storedData->save();
114
+	}
115
+
116
+	public function getProvisioningUrl(User $user)
117
+	{
118
+		$storedData = $this->getCredentialData($user->getId(), true);
119
+
120
+		if ($storedData->getTimeout() < new DateTimeImmutable()) {
121
+			$storedData->delete();
122
+			$storedData = null;
123
+		}
124
+
125
+		if ($storedData === null) {
126
+			throw new ApplicationLogicException('Credential data not found');
127
+		}
128
+
129
+		return $this->encryptionHelper->decryptData($storedData->getData());
130
+	}
131
+
132
+	public function isPartiallyEnrolled(User $user)
133
+	{
134
+		$storedData = $this->getCredentialData($user->getId(), true);
135
+
136
+		if ($storedData->getTimeout() < new DateTimeImmutable()) {
137
+			$storedData->delete();
138
+
139
+			return false;
140
+		}
141
+
142
+		if ($storedData === null) {
143
+			return false;
144
+		}
145 145
 
146
-        return true;
147
-    }
146
+		return true;
147
+	}
148 148
 
149
-    public function getSecret(User $user)
150
-    {
151
-        $totp = Factory::loadFromProvisioningUri($this->getProvisioningUrl($user));
149
+	public function getSecret(User $user)
150
+	{
151
+		$totp = Factory::loadFromProvisioningUri($this->getProvisioningUrl($user));
152 152
 
153
-        return $totp->getSecret();
154
-    }
153
+		return $totp->getSecret();
154
+	}
155 155
 }
Please login to merge, or discard this patch.
includes/Security/CredentialProviders/PasswordCredentialProvider.php 3 patches
Indentation   +109 added lines, -109 removed lines patch added patch discarded remove patch
@@ -19,123 +19,123 @@
 block discarded – undo
19 19
 
20 20
 class PasswordCredentialProvider extends CredentialProviderBase
21 21
 {
22
-    const PASSWORD_COST = 10;
23
-    const PASSWORD_ALGO = PASSWORD_BCRYPT;
24
-
25
-    public function __construct(PdoDatabase $database, SiteConfiguration $configuration)
26
-    {
27
-        parent::__construct($database, $configuration, 'password');
28
-    }
29
-
30
-    public function authenticate(User $user, $data)
31
-    {
32
-        $storedData = $this->getCredentialData($user->getId());
33
-        if($storedData === null)
34
-        {
35
-            // No available credential matching these parameters
36
-            return false;
37
-        }
38
-
39
-        if($storedData->getVersion() !== 2) {
40
-            // Non-2 versions are not supported.
41
-            return false;
42
-        }
43
-
44
-        if (!password_verify($data, $storedData->getData())) {
45
-            return false;
46
-        }
47
-
48
-        if (password_needs_rehash($storedData->getData(), self::PASSWORD_ALGO,
49
-            array('cost' => self::PASSWORD_COST))) {
50
-            try {
51
-                $this->reallySetCredential($user, $storedData->getFactor(), $data);
52
-            }
53
-            catch (OptimisticLockFailedException $e) {
54
-                // optimistic lock failed, but no biggie. We'll catch it on the next login.
55
-            }
56
-        }
57
-
58
-        $strengthTester = new Zxcvbn();
59
-        $strength = $strengthTester->passwordStrength($data, [$user->getUsername(), $user->getOnWikiName(), $user->getEmail()]);
60
-
61
-        /*  0 means the password is extremely guessable (within 10^3 guesses), dictionary words like 'password' or 'mother' score a 0
22
+	const PASSWORD_COST = 10;
23
+	const PASSWORD_ALGO = PASSWORD_BCRYPT;
24
+
25
+	public function __construct(PdoDatabase $database, SiteConfiguration $configuration)
26
+	{
27
+		parent::__construct($database, $configuration, 'password');
28
+	}
29
+
30
+	public function authenticate(User $user, $data)
31
+	{
32
+		$storedData = $this->getCredentialData($user->getId());
33
+		if($storedData === null)
34
+		{
35
+			// No available credential matching these parameters
36
+			return false;
37
+		}
38
+
39
+		if($storedData->getVersion() !== 2) {
40
+			// Non-2 versions are not supported.
41
+			return false;
42
+		}
43
+
44
+		if (!password_verify($data, $storedData->getData())) {
45
+			return false;
46
+		}
47
+
48
+		if (password_needs_rehash($storedData->getData(), self::PASSWORD_ALGO,
49
+			array('cost' => self::PASSWORD_COST))) {
50
+			try {
51
+				$this->reallySetCredential($user, $storedData->getFactor(), $data);
52
+			}
53
+			catch (OptimisticLockFailedException $e) {
54
+				// optimistic lock failed, but no biggie. We'll catch it on the next login.
55
+			}
56
+		}
57
+
58
+		$strengthTester = new Zxcvbn();
59
+		$strength = $strengthTester->passwordStrength($data, [$user->getUsername(), $user->getOnWikiName(), $user->getEmail()]);
60
+
61
+		/*  0 means the password is extremely guessable (within 10^3 guesses), dictionary words like 'password' or 'mother' score a 0
62 62
             1 is still very guessable (guesses < 10^6), an extra character on a dictionary word can score a 1
63 63
             2 is somewhat guessable (guesses < 10^8), provides some protection from unthrottled online attacks
64 64
             3 is safely unguessable (guesses < 10^10), offers moderate protection from offline slow-hash scenario
65 65
             4 is very unguessable (guesses >= 10^10) and provides strong protection from offline slow-hash scenario         */
66 66
 
67
-        if ($strength['score'] <= 1 || PasswordBlacklist::isBlacklisted($data) || mb_strlen($data) < 8) {
68
-            // prevent login for extremely weak passwords
69
-            // at this point the user has authenticated via password, so they *know* it's weak.
70
-            SessionAlert::error('Your password is too weak to permit login. Please choose the "forgotten your password" option below and set a new one.', null);
71
-            return false;
72
-        }
73
-
74
-        return true;
75
-    }
76
-
77
-    /**
78
-     * @param User   $user
79
-     * @param int    $factor
80
-     * @param string $password
81
-     *
82
-     * @throws OptimisticLockFailedException
83
-     */
84
-    private function reallySetCredential(User $user, int $factor, string $password) : void {
85
-        $storedData = $this->getCredentialData($user->getId());
86
-
87
-        if ($storedData === null) {
88
-            $storedData = $this->createNewCredential($user);
89
-        }
90
-
91
-        $storedData->setData(password_hash($password, self::PASSWORD_ALGO, array('cost' => self::PASSWORD_COST)));
92
-        $storedData->setFactor($factor);
93
-        $storedData->setVersion(2);
94
-
95
-        $storedData->save();
96
-    }
97
-
98
-    /**
99
-     * @param User   $user
100
-     * @param int    $factor
101
-     * @param string $password
102
-     *
103
-     * @throws ApplicationLogicException
104
-     * @throws OptimisticLockFailedException
105
-     */
106
-    public function setCredential(User $user, $factor, $password)
107
-    {
108
-        if (PasswordBlacklist::isBlacklisted($password)) {
109
-            throw new ApplicationLogicException("Your new password is listed in the top 100,000 passwords. Please choose a stronger one.", null);
110
-        }
111
-
112
-        $strengthTester = new Zxcvbn();
113
-        $strength = $strengthTester->passwordStrength($password, [$user->getUsername(), $user->getOnWikiName(), $user->getEmail()]);
114
-
115
-        /*  0 means the password is extremely guessable (within 10^3 guesses), dictionary words like 'password' or 'mother' score a 0
67
+		if ($strength['score'] <= 1 || PasswordBlacklist::isBlacklisted($data) || mb_strlen($data) < 8) {
68
+			// prevent login for extremely weak passwords
69
+			// at this point the user has authenticated via password, so they *know* it's weak.
70
+			SessionAlert::error('Your password is too weak to permit login. Please choose the "forgotten your password" option below and set a new one.', null);
71
+			return false;
72
+		}
73
+
74
+		return true;
75
+	}
76
+
77
+	/**
78
+	 * @param User   $user
79
+	 * @param int    $factor
80
+	 * @param string $password
81
+	 *
82
+	 * @throws OptimisticLockFailedException
83
+	 */
84
+	private function reallySetCredential(User $user, int $factor, string $password) : void {
85
+		$storedData = $this->getCredentialData($user->getId());
86
+
87
+		if ($storedData === null) {
88
+			$storedData = $this->createNewCredential($user);
89
+		}
90
+
91
+		$storedData->setData(password_hash($password, self::PASSWORD_ALGO, array('cost' => self::PASSWORD_COST)));
92
+		$storedData->setFactor($factor);
93
+		$storedData->setVersion(2);
94
+
95
+		$storedData->save();
96
+	}
97
+
98
+	/**
99
+	 * @param User   $user
100
+	 * @param int    $factor
101
+	 * @param string $password
102
+	 *
103
+	 * @throws ApplicationLogicException
104
+	 * @throws OptimisticLockFailedException
105
+	 */
106
+	public function setCredential(User $user, $factor, $password)
107
+	{
108
+		if (PasswordBlacklist::isBlacklisted($password)) {
109
+			throw new ApplicationLogicException("Your new password is listed in the top 100,000 passwords. Please choose a stronger one.", null);
110
+		}
111
+
112
+		$strengthTester = new Zxcvbn();
113
+		$strength = $strengthTester->passwordStrength($password, [$user->getUsername(), $user->getOnWikiName(), $user->getEmail()]);
114
+
115
+		/*  0 means the password is extremely guessable (within 10^3 guesses), dictionary words like 'password' or 'mother' score a 0
116 116
             1 is still very guessable (guesses < 10^6), an extra character on a dictionary word can score a 1
117 117
             2 is somewhat guessable (guesses < 10^8), provides some protection from unthrottled online attacks
118 118
             3 is safely unguessable (guesses < 10^10), offers moderate protection from offline slow-hash scenario
119 119
             4 is very unguessable (guesses >= 10^10) and provides strong protection from offline slow-hash scenario         */
120 120
 
121
-        if ($strength['score'] <= 2 || mb_strlen($password) < 8) {
122
-            throw new ApplicationLogicException("Your new password is too weak. Please choose a stronger one.", null);
123
-        }
124
-
125
-        if ($strength['score'] <= 3) {
126
-            SessionAlert::warning("Your new password is not as strong as it could be. Consider replacing it with a stronger password.", null);
127
-        }
128
-
129
-        $this->reallySetCredential($user, $factor, $password);
130
-    }
131
-
132
-    /**
133
-     * @param User $user
134
-     *
135
-     * @throws ApplicationLogicException
136
-     */
137
-    public function deleteCredential(User $user)
138
-    {
139
-        throw new ApplicationLogicException('Deletion of password credential is not allowed.');
140
-    }
121
+		if ($strength['score'] <= 2 || mb_strlen($password) < 8) {
122
+			throw new ApplicationLogicException("Your new password is too weak. Please choose a stronger one.", null);
123
+		}
124
+
125
+		if ($strength['score'] <= 3) {
126
+			SessionAlert::warning("Your new password is not as strong as it could be. Consider replacing it with a stronger password.", null);
127
+		}
128
+
129
+		$this->reallySetCredential($user, $factor, $password);
130
+	}
131
+
132
+	/**
133
+	 * @param User $user
134
+	 *
135
+	 * @throws ApplicationLogicException
136
+	 */
137
+	public function deleteCredential(User $user)
138
+	{
139
+		throw new ApplicationLogicException('Deletion of password credential is not allowed.');
140
+	}
141 141
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -30,13 +30,13 @@
 block discarded – undo
30 30
     public function authenticate(User $user, $data)
31 31
     {
32 32
         $storedData = $this->getCredentialData($user->getId());
33
-        if($storedData === null)
33
+        if ($storedData === null)
34 34
         {
35 35
             // No available credential matching these parameters
36 36
             return false;
37 37
         }
38 38
 
39
-        if($storedData->getVersion() !== 2) {
39
+        if ($storedData->getVersion() !== 2) {
40 40
             // Non-2 versions are not supported.
41 41
             return false;
42 42
         }
Please login to merge, or discard this patch.
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -30,8 +30,7 @@
 block discarded – undo
30 30
     public function authenticate(User $user, $data)
31 31
     {
32 32
         $storedData = $this->getCredentialData($user->getId());
33
-        if($storedData === null)
34
-        {
33
+        if($storedData === null) {
35 34
             // No available credential matching these parameters
36 35
             return false;
37 36
         }
Please login to merge, or discard this patch.
includes/Security/CredentialProviders/ICredentialProvider.php 1 patch
Indentation   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -12,32 +12,32 @@
 block discarded – undo
12 12
 
13 13
 interface ICredentialProvider
14 14
 {
15
-    /**
16
-     * Validates a user-provided credential
17
-     *
18
-     * @param User $user The user to test the authentication against
19
-     * @param string $data The raw credential data to be validated
20
-     *
21
-     * @return bool
22
-     */
23
-    public function authenticate(User $user, $data);
15
+	/**
16
+	 * Validates a user-provided credential
17
+	 *
18
+	 * @param User $user The user to test the authentication against
19
+	 * @param string $data The raw credential data to be validated
20
+	 *
21
+	 * @return bool
22
+	 */
23
+	public function authenticate(User $user, $data);
24 24
 
25
-    /**
26
-     * @param User $user The user the credential belongs to
27
-     * @param int $factor The factor this credential provides
28
-     * @param string $data
29
-     */
30
-    public function setCredential(User $user, $factor, $data);
25
+	/**
26
+	 * @param User $user The user the credential belongs to
27
+	 * @param int $factor The factor this credential provides
28
+	 * @param string $data
29
+	 */
30
+	public function setCredential(User $user, $factor, $data);
31 31
 
32
-    /**
33
-     * @param User $user
34
-     */
35
-    public function deleteCredential(User $user);
32
+	/**
33
+	 * @param User $user
34
+	 */
35
+	public function deleteCredential(User $user);
36 36
 
37
-    /**
38
-     * @param int $userId
39
-     *
40
-     * @return bool
41
-     */
42
-    public function userIsEnrolled($userId);
37
+	/**
38
+	 * @param int $userId
39
+	 *
40
+	 * @return bool
41
+	 */
42
+	public function userIsEnrolled($userId);
43 43
 }
44 44
\ No newline at end of file
Please login to merge, or discard this patch.
includes/Security/CredentialProviders/YubikeyOtpCredentialProvider.php 1 patch
Indentation   +150 added lines, -150 removed lines patch added patch discarded remove patch
@@ -16,154 +16,154 @@
 block discarded – undo
16 16
 
17 17
 class YubikeyOtpCredentialProvider extends CredentialProviderBase
18 18
 {
19
-    /** @var HttpHelper */
20
-    private $httpHelper;
21
-    /**
22
-     * @var SiteConfiguration
23
-     */
24
-    private $configuration;
25
-
26
-    public function __construct(PdoDatabase $database, SiteConfiguration $configuration, HttpHelper $httpHelper)
27
-    {
28
-        parent::__construct($database, $configuration, 'yubikeyotp');
29
-        $this->httpHelper = $httpHelper;
30
-        $this->configuration = $configuration;
31
-    }
32
-
33
-    public function authenticate(User $user, $data)
34
-    {
35
-        if (is_array($data)) {
36
-            return false;
37
-        }
38
-
39
-        $credentialData = $this->getCredentialData($user->getId());
40
-
41
-        if ($credentialData === null) {
42
-            return false;
43
-        }
44
-
45
-        if ($credentialData->getData() !== $this->getYubikeyId($data)) {
46
-            // different device
47
-            return false;
48
-        }
49
-
50
-        return $this->verifyToken($data);
51
-    }
52
-
53
-    public function setCredential(User $user, $factor, $data)
54
-    {
55
-        $keyId = $this->getYubikeyId($data);
56
-        $valid = $this->verifyToken($data);
57
-
58
-        if (!$valid) {
59
-            throw new ApplicationLogicException("Provided token is not valid.");
60
-        }
61
-
62
-        $storedData = $this->getCredentialData($user->getId());
63
-
64
-        if ($storedData === null) {
65
-            $storedData = $this->createNewCredential($user);
66
-        }
67
-
68
-        $storedData->setData($keyId);
69
-        $storedData->setFactor($factor);
70
-        $storedData->setVersion(1);
71
-        $storedData->setPriority(8);
72
-
73
-        $storedData->save();
74
-    }
75
-
76
-    /**
77
-     * Get the Yubikey ID.
78
-     *
79
-     * This looks like it's just dumping the "password" that's stored in the database, but it's actually fine.
80
-     *
81
-     * We only store the "serial number" of the Yubikey - if we get a validated (by webservice) token prefixed with the
82
-     * serial number, that's a successful OTP authentication. Thus, retrieving the stored data is just retrieving the
83
-     * yubikey's serial number (in modhex format), since the actual security credentials are stored on the device.
84
-     *
85
-     * Note that the serial number is actually the credential serial number - it's possible to regenerate the keys on
86
-     * the device, and that will change the serial number too.
87
-     *
88
-     * More information about the structure of OTPs can be found here:
89
-     * https://developers.yubico.com/OTP/OTPs_Explained.html
90
-     *
91
-     * @param int $userId
92
-     *
93
-     * @return null|string
94
-     */
95
-    public function getYubikeyData($userId)
96
-    {
97
-        $credential = $this->getCredentialData($userId);
98
-
99
-        if ($credential === null) {
100
-            return null;
101
-        }
102
-
103
-        return $credential->getData();
104
-    }
105
-
106
-    /**
107
-     * @param $result
108
-     *
109
-     * @return array
110
-     */
111
-    private function parseYubicoApiResult($result)
112
-    {
113
-        $data = array();
114
-        foreach (explode("\r\n", $result) as $line) {
115
-            $pos = strpos($line, '=');
116
-            if ($pos === false) {
117
-                continue;
118
-            }
119
-
120
-            $data[substr($line, 0, $pos)] = substr($line, $pos + 1);
121
-        }
122
-
123
-        return $data;
124
-    }
125
-
126
-    private function getYubikeyId($data)
127
-    {
128
-        return substr($data, 0, -32);
129
-    }
130
-
131
-    private function verifyHmac($apiResponse, $apiKey)
132
-    {
133
-        ksort($apiResponse);
134
-        $signature = $apiResponse['h'];
135
-        unset($apiResponse['h']);
136
-
137
-        $data = array();
138
-        foreach ($apiResponse as $key => $value) {
139
-            $data[] = $key . "=" . $value;
140
-        }
141
-        $dataString = implode('&', $data);
142
-
143
-        $hmac = base64_encode(hash_hmac('sha1', $dataString, base64_decode($apiKey), true));
144
-
145
-        return $hmac === $signature;
146
-    }
147
-
148
-    /**
149
-     * @param $data
150
-     *
151
-     * @return bool
152
-     */
153
-    private function verifyToken($data)
154
-    {
155
-        $result = $this->httpHelper->get('https://api.yubico.com/wsapi/2.0/verify', array(
156
-            'id'    => $this->configuration->getYubicoApiId(),
157
-            'otp'   => $data,
158
-            'nonce' => md5(openssl_random_pseudo_bytes(64)),
159
-        ));
160
-
161
-        $apiResponse = $this->parseYubicoApiResult($result);
162
-
163
-        if (!$this->verifyHmac($apiResponse, $this->configuration->getYubicoApiKey())) {
164
-            return false;
165
-        }
166
-
167
-        return $apiResponse['status'] == 'OK';
168
-    }
19
+	/** @var HttpHelper */
20
+	private $httpHelper;
21
+	/**
22
+	 * @var SiteConfiguration
23
+	 */
24
+	private $configuration;
25
+
26
+	public function __construct(PdoDatabase $database, SiteConfiguration $configuration, HttpHelper $httpHelper)
27
+	{
28
+		parent::__construct($database, $configuration, 'yubikeyotp');
29
+		$this->httpHelper = $httpHelper;
30
+		$this->configuration = $configuration;
31
+	}
32
+
33
+	public function authenticate(User $user, $data)
34
+	{
35
+		if (is_array($data)) {
36
+			return false;
37
+		}
38
+
39
+		$credentialData = $this->getCredentialData($user->getId());
40
+
41
+		if ($credentialData === null) {
42
+			return false;
43
+		}
44
+
45
+		if ($credentialData->getData() !== $this->getYubikeyId($data)) {
46
+			// different device
47
+			return false;
48
+		}
49
+
50
+		return $this->verifyToken($data);
51
+	}
52
+
53
+	public function setCredential(User $user, $factor, $data)
54
+	{
55
+		$keyId = $this->getYubikeyId($data);
56
+		$valid = $this->verifyToken($data);
57
+
58
+		if (!$valid) {
59
+			throw new ApplicationLogicException("Provided token is not valid.");
60
+		}
61
+
62
+		$storedData = $this->getCredentialData($user->getId());
63
+
64
+		if ($storedData === null) {
65
+			$storedData = $this->createNewCredential($user);
66
+		}
67
+
68
+		$storedData->setData($keyId);
69
+		$storedData->setFactor($factor);
70
+		$storedData->setVersion(1);
71
+		$storedData->setPriority(8);
72
+
73
+		$storedData->save();
74
+	}
75
+
76
+	/**
77
+	 * Get the Yubikey ID.
78
+	 *
79
+	 * This looks like it's just dumping the "password" that's stored in the database, but it's actually fine.
80
+	 *
81
+	 * We only store the "serial number" of the Yubikey - if we get a validated (by webservice) token prefixed with the
82
+	 * serial number, that's a successful OTP authentication. Thus, retrieving the stored data is just retrieving the
83
+	 * yubikey's serial number (in modhex format), since the actual security credentials are stored on the device.
84
+	 *
85
+	 * Note that the serial number is actually the credential serial number - it's possible to regenerate the keys on
86
+	 * the device, and that will change the serial number too.
87
+	 *
88
+	 * More information about the structure of OTPs can be found here:
89
+	 * https://developers.yubico.com/OTP/OTPs_Explained.html
90
+	 *
91
+	 * @param int $userId
92
+	 *
93
+	 * @return null|string
94
+	 */
95
+	public function getYubikeyData($userId)
96
+	{
97
+		$credential = $this->getCredentialData($userId);
98
+
99
+		if ($credential === null) {
100
+			return null;
101
+		}
102
+
103
+		return $credential->getData();
104
+	}
105
+
106
+	/**
107
+	 * @param $result
108
+	 *
109
+	 * @return array
110
+	 */
111
+	private function parseYubicoApiResult($result)
112
+	{
113
+		$data = array();
114
+		foreach (explode("\r\n", $result) as $line) {
115
+			$pos = strpos($line, '=');
116
+			if ($pos === false) {
117
+				continue;
118
+			}
119
+
120
+			$data[substr($line, 0, $pos)] = substr($line, $pos + 1);
121
+		}
122
+
123
+		return $data;
124
+	}
125
+
126
+	private function getYubikeyId($data)
127
+	{
128
+		return substr($data, 0, -32);
129
+	}
130
+
131
+	private function verifyHmac($apiResponse, $apiKey)
132
+	{
133
+		ksort($apiResponse);
134
+		$signature = $apiResponse['h'];
135
+		unset($apiResponse['h']);
136
+
137
+		$data = array();
138
+		foreach ($apiResponse as $key => $value) {
139
+			$data[] = $key . "=" . $value;
140
+		}
141
+		$dataString = implode('&', $data);
142
+
143
+		$hmac = base64_encode(hash_hmac('sha1', $dataString, base64_decode($apiKey), true));
144
+
145
+		return $hmac === $signature;
146
+	}
147
+
148
+	/**
149
+	 * @param $data
150
+	 *
151
+	 * @return bool
152
+	 */
153
+	private function verifyToken($data)
154
+	{
155
+		$result = $this->httpHelper->get('https://api.yubico.com/wsapi/2.0/verify', array(
156
+			'id'    => $this->configuration->getYubicoApiId(),
157
+			'otp'   => $data,
158
+			'nonce' => md5(openssl_random_pseudo_bytes(64)),
159
+		));
160
+
161
+		$apiResponse = $this->parseYubicoApiResult($result);
162
+
163
+		if (!$this->verifyHmac($apiResponse, $this->configuration->getYubicoApiKey())) {
164
+			return false;
165
+		}
166
+
167
+		return $apiResponse['status'] == 'OK';
168
+	}
169 169
 }
Please login to merge, or discard this patch.
includes/Security/RoleConfiguration.php 1 patch
Indentation   +360 added lines, -360 removed lines patch added patch discarded remove patch
@@ -47,391 +47,391 @@
 block discarded – undo
47 47
 
48 48
 class RoleConfiguration
49 49
 {
50
-    const ACCESS_ALLOW = 1;
51
-    const ACCESS_DENY = -1;
52
-    const ACCESS_DEFAULT = 0;
53
-    const MAIN = 'main';
54
-    const ALL = '*';
55
-    /**
56
-     * A map of roles to rights
57
-     *
58
-     * For example:
59
-     *
60
-     * array(
61
-     *   'myrole' => array(
62
-     *       PageMyPage::class => array(
63
-     *           'edit' => self::ACCESS_ALLOW,
64
-     *           'create' => self::ACCESS_DENY,
65
-     *       )
66
-     *   )
67
-     * )
68
-     *
69
-     * Note that DENY takes precedence over everything else when roles are combined, followed by ALLOW, followed by
70
-     * DEFAULT. Thus, if you have the following ([A]llow, [D]eny, [-] (default)) grants in different roles, this should
71
-     * be the expected result:
72
-     *
73
-     * - (-,-,-) = - (default because nothing to explicitly say allowed or denied equates to a denial)
74
-     * - (A,-,-) = A
75
-     * - (D,-,-) = D
76
-     * - (A,D,-) = D (deny takes precedence over allow)
77
-     * - (A,A,A) = A (repetition has no effect)
78
-     *
79
-     * The public role is special, and is applied to all users automatically. Avoid using deny on this role.
80
-     *
81
-     * @var array
82
-     */
83
-    private $roleConfig = array(
84
-        'public'            => array(
85
-            /*
50
+	const ACCESS_ALLOW = 1;
51
+	const ACCESS_DENY = -1;
52
+	const ACCESS_DEFAULT = 0;
53
+	const MAIN = 'main';
54
+	const ALL = '*';
55
+	/**
56
+	 * A map of roles to rights
57
+	 *
58
+	 * For example:
59
+	 *
60
+	 * array(
61
+	 *   'myrole' => array(
62
+	 *       PageMyPage::class => array(
63
+	 *           'edit' => self::ACCESS_ALLOW,
64
+	 *           'create' => self::ACCESS_DENY,
65
+	 *       )
66
+	 *   )
67
+	 * )
68
+	 *
69
+	 * Note that DENY takes precedence over everything else when roles are combined, followed by ALLOW, followed by
70
+	 * DEFAULT. Thus, if you have the following ([A]llow, [D]eny, [-] (default)) grants in different roles, this should
71
+	 * be the expected result:
72
+	 *
73
+	 * - (-,-,-) = - (default because nothing to explicitly say allowed or denied equates to a denial)
74
+	 * - (A,-,-) = A
75
+	 * - (D,-,-) = D
76
+	 * - (A,D,-) = D (deny takes precedence over allow)
77
+	 * - (A,A,A) = A (repetition has no effect)
78
+	 *
79
+	 * The public role is special, and is applied to all users automatically. Avoid using deny on this role.
80
+	 *
81
+	 * @var array
82
+	 */
83
+	private $roleConfig = array(
84
+		'public'            => array(
85
+			/*
86 86
              * THIS ROLE IS GRANTED TO ALL LOGGED *OUT* USERS IMPLICITLY.
87 87
              *
88 88
              * USERS IN THIS ROLE DO NOT HAVE TO BE IDENTIFIED TO GET THE RIGHTS CONFERRED HERE.
89 89
              * DO NOT ADD ANY SECURITY-SENSITIVE RIGHTS HERE.
90 90
              */
91
-            '_childRoles'   => array(
92
-                'publicStats',
93
-            ),
94
-            PageTeam::class => array(
95
-                self::MAIN => self::ACCESS_ALLOW,
96
-            ),
97
-            PageXffDemo::class        => array(
98
-                self::MAIN  => self::ACCESS_ALLOW,
99
-            )
100
-        ),
101
-        'loggedIn'          => array(
102
-            /*
91
+			'_childRoles'   => array(
92
+				'publicStats',
93
+			),
94
+			PageTeam::class => array(
95
+				self::MAIN => self::ACCESS_ALLOW,
96
+			),
97
+			PageXffDemo::class        => array(
98
+				self::MAIN  => self::ACCESS_ALLOW,
99
+			)
100
+		),
101
+		'loggedIn'          => array(
102
+			/*
103 103
              * THIS ROLE IS GRANTED TO ALL LOGGED IN USERS IMPLICITLY.
104 104
              *
105 105
              * USERS IN THIS ROLE DO NOT HAVE TO BE IDENTIFIED TO GET THE RIGHTS CONFERRED HERE.
106 106
              * DO NOT ADD ANY SECURITY-SENSITIVE RIGHTS HERE.
107 107
              */
108
-            '_childRoles'             => array(
109
-                'public',
110
-            ),
111
-            PagePreferences::class    => array(
112
-                self::MAIN => self::ACCESS_ALLOW,
113
-                'refreshOAuth' => self::ACCESS_ALLOW,
114
-            ),
115
-            PageChangePassword::class => array(
116
-                self::MAIN => self::ACCESS_ALLOW,
117
-            ),
118
-            PageMultiFactor::class    => array(
119
-                self::MAIN          => self::ACCESS_ALLOW,
120
-                'scratch'           => self::ACCESS_ALLOW,
121
-                'enableYubikeyOtp'  => self::ACCESS_ALLOW,
122
-                'disableYubikeyOtp' => self::ACCESS_ALLOW,
123
-                'enableTotp'        => self::ACCESS_ALLOW,
124
-                'disableTotp'       => self::ACCESS_ALLOW,
125
-            ),
126
-            PageOAuth::class          => array(
127
-                'attach' => self::ACCESS_ALLOW,
128
-                'detach' => self::ACCESS_ALLOW,
129
-            ),
130
-        ),
131
-        'user'              => array(
132
-            '_description'                       => 'A standard tool user.',
133
-            '_editableBy'                        => array('admin', 'toolRoot'),
134
-            '_childRoles'                        => array(
135
-                'internalStats',
136
-            ),
137
-            PageMain::class                      => array(
138
-                self::MAIN => self::ACCESS_ALLOW,
139
-            ),
140
-            PageBan::class                       => array(
141
-                self::MAIN => self::ACCESS_ALLOW,
142
-            ),
143
-            PageEditComment::class               => array(
144
-                self::MAIN => self::ACCESS_ALLOW,
145
-            ),
146
-            PageEmailManagement::class           => array(
147
-                self::MAIN => self::ACCESS_ALLOW,
148
-                'view'     => self::ACCESS_ALLOW,
149
-            ),
150
-            PageExpandedRequestList::class       => array(
151
-                self::MAIN => self::ACCESS_ALLOW,
152
-            ),
153
-            PageLog::class                       => array(
154
-                self::MAIN => self::ACCESS_ALLOW,
155
-            ),
156
-            PageSearch::class                    => array(
157
-                self::MAIN => self::ACCESS_ALLOW,
158
-            ),
159
-            PageWelcomeTemplateManagement::class => array(
160
-                self::MAIN => self::ACCESS_ALLOW,
161
-                'select'   => self::ACCESS_ALLOW,
162
-                'view'     => self::ACCESS_ALLOW,
163
-            ),
164
-            PageViewRequest::class               => array(
165
-                self::MAIN       => self::ACCESS_ALLOW,
166
-                'seeAllRequests' => self::ACCESS_ALLOW,
167
-            ),
168
-            'RequestData'                        => array(
169
-                'seePrivateDataWhenReserved' => self::ACCESS_ALLOW,
170
-                'seePrivateDataWithHash'     => self::ACCESS_ALLOW,
171
-            ),
172
-            PageCustomClose::class               => array(
173
-                self::MAIN => self::ACCESS_ALLOW,
174
-            ),
175
-            PageComment::class                   => array(
176
-                self::MAIN => self::ACCESS_ALLOW,
177
-            ),
178
-            PageCloseRequest::class              => array(
179
-                self::MAIN => self::ACCESS_ALLOW,
180
-            ),
181
-            PageCreateRequest::class             => array(
182
-                self::MAIN => self::ACCESS_ALLOW,
183
-            ),
184
-            PageDeferRequest::class              => array(
185
-                self::MAIN => self::ACCESS_ALLOW,
186
-            ),
187
-            PageDropRequest::class               => array(
188
-                self::MAIN => self::ACCESS_ALLOW,
189
-            ),
190
-            PageReservation::class               => array(
191
-                self::MAIN => self::ACCESS_ALLOW,
192
-            ),
193
-            PageSendToUser::class                => array(
194
-                self::MAIN => self::ACCESS_ALLOW,
195
-            ),
196
-            PageBreakReservation::class          => array(
197
-                self::MAIN => self::ACCESS_ALLOW,
198
-            ),
199
-            PageJobQueue::class                  => array(
200
-                self::MAIN => self::ACCESS_ALLOW,
201
-                'view'     => self::ACCESS_ALLOW,
202
-                'all'      => self::ACCESS_ALLOW,
203
-            ),
204
-            'RequestCreation'                    => array(
205
-                User::CREATION_MANUAL => self::ACCESS_ALLOW,
206
-            ),
207
-            'GlobalInfo'                         => array(
208
-                'viewSiteNotice' => self::ACCESS_ALLOW,
209
-                'viewOnlineUsers' => self::ACCESS_ALLOW,
210
-            ),
211
-        ),
212
-        'admin'             => array(
213
-            '_description'                       => 'A tool administrator.',
214
-            '_editableBy'                        => array('admin', 'toolRoot'),
215
-            '_childRoles'                        => array(
216
-                'user',
217
-                'requestAdminTools',
218
-            ),
219
-            PageEmailManagement::class           => array(
220
-                'edit'   => self::ACCESS_ALLOW,
221
-                'create' => self::ACCESS_ALLOW,
222
-            ),
223
-            PageSiteNotice::class                => array(
224
-                self::MAIN => self::ACCESS_ALLOW,
225
-            ),
226
-            PageUserManagement::class            => array(
227
-                self::MAIN  => self::ACCESS_ALLOW,
228
-                'approve'   => self::ACCESS_ALLOW,
229
-                'decline'   => self::ACCESS_ALLOW,
230
-                'rename'    => self::ACCESS_ALLOW,
231
-                'editUser'  => self::ACCESS_ALLOW,
232
-                'suspend'   => self::ACCESS_ALLOW,
233
-                'editRoles' => self::ACCESS_ALLOW,
234
-            ),
235
-            PageWelcomeTemplateManagement::class => array(
236
-                'edit'   => self::ACCESS_ALLOW,
237
-                'delete' => self::ACCESS_ALLOW,
238
-                'add'    => self::ACCESS_ALLOW,
239
-            ),
240
-            PageJobQueue::class                  => array(
241
-                'acknowledge' => self::ACCESS_ALLOW,
242
-                'requeue'     => self::ACCESS_ALLOW,
243
-            ),
244
-        ),
245
-        'checkuser'         => array(
246
-            '_description'            => 'A user with CheckUser access',
247
-            '_editableBy'             => array('checkuser', 'toolRoot'),
248
-            '_childRoles'             => array(
249
-                'user',
250
-                'requestAdminTools',
251
-            ),
252
-            PageUserManagement::class => array(
253
-                self::MAIN  => self::ACCESS_ALLOW,
254
-                'suspend'   => self::ACCESS_ALLOW,
255
-                'editRoles' => self::ACCESS_ALLOW,
256
-            ),
257
-            'RequestData'             => array(
258
-                'seeUserAgentData' => self::ACCESS_ALLOW,
259
-            ),
260
-        ),
261
-        'toolRoot'          => array(
262
-            '_description' => 'A user with shell access to the servers running the tool',
263
-            '_editableBy'  => array('toolRoot'),
264
-            '_childRoles'  => array(
265
-                'admin',
266
-            ),
267
-            PageMultiFactor::class => array(
268
-                'enableU2F'         => self::ACCESS_ALLOW,
269
-                'disableU2F'        => self::ACCESS_ALLOW,
270
-            )
271
-        ),
272
-        'botCreation'       => array(
273
-            '_description'    => 'A user allowed to use the bot to perform account creations',
274
-            '_editableBy'     => array('admin', 'toolRoot'),
275
-            '_childRoles'     => array(),
276
-            'RequestCreation' => array(
277
-                User::CREATION_BOT => self::ACCESS_ALLOW,
278
-            ),
279
-        ),
280
-        'oauthCreation'       => array(
281
-            '_description'    => 'A user allowed to use the OAuth to perform account creations',
282
-            '_editableBy'     => array('admin', 'toolRoot'),
283
-            '_childRoles'     => array(),
284
-            'RequestCreation'                    => array(
285
-                User::CREATION_OAUTH  => self::ACCESS_ALLOW,
286
-            ),
287
-        ),
108
+			'_childRoles'             => array(
109
+				'public',
110
+			),
111
+			PagePreferences::class    => array(
112
+				self::MAIN => self::ACCESS_ALLOW,
113
+				'refreshOAuth' => self::ACCESS_ALLOW,
114
+			),
115
+			PageChangePassword::class => array(
116
+				self::MAIN => self::ACCESS_ALLOW,
117
+			),
118
+			PageMultiFactor::class    => array(
119
+				self::MAIN          => self::ACCESS_ALLOW,
120
+				'scratch'           => self::ACCESS_ALLOW,
121
+				'enableYubikeyOtp'  => self::ACCESS_ALLOW,
122
+				'disableYubikeyOtp' => self::ACCESS_ALLOW,
123
+				'enableTotp'        => self::ACCESS_ALLOW,
124
+				'disableTotp'       => self::ACCESS_ALLOW,
125
+			),
126
+			PageOAuth::class          => array(
127
+				'attach' => self::ACCESS_ALLOW,
128
+				'detach' => self::ACCESS_ALLOW,
129
+			),
130
+		),
131
+		'user'              => array(
132
+			'_description'                       => 'A standard tool user.',
133
+			'_editableBy'                        => array('admin', 'toolRoot'),
134
+			'_childRoles'                        => array(
135
+				'internalStats',
136
+			),
137
+			PageMain::class                      => array(
138
+				self::MAIN => self::ACCESS_ALLOW,
139
+			),
140
+			PageBan::class                       => array(
141
+				self::MAIN => self::ACCESS_ALLOW,
142
+			),
143
+			PageEditComment::class               => array(
144
+				self::MAIN => self::ACCESS_ALLOW,
145
+			),
146
+			PageEmailManagement::class           => array(
147
+				self::MAIN => self::ACCESS_ALLOW,
148
+				'view'     => self::ACCESS_ALLOW,
149
+			),
150
+			PageExpandedRequestList::class       => array(
151
+				self::MAIN => self::ACCESS_ALLOW,
152
+			),
153
+			PageLog::class                       => array(
154
+				self::MAIN => self::ACCESS_ALLOW,
155
+			),
156
+			PageSearch::class                    => array(
157
+				self::MAIN => self::ACCESS_ALLOW,
158
+			),
159
+			PageWelcomeTemplateManagement::class => array(
160
+				self::MAIN => self::ACCESS_ALLOW,
161
+				'select'   => self::ACCESS_ALLOW,
162
+				'view'     => self::ACCESS_ALLOW,
163
+			),
164
+			PageViewRequest::class               => array(
165
+				self::MAIN       => self::ACCESS_ALLOW,
166
+				'seeAllRequests' => self::ACCESS_ALLOW,
167
+			),
168
+			'RequestData'                        => array(
169
+				'seePrivateDataWhenReserved' => self::ACCESS_ALLOW,
170
+				'seePrivateDataWithHash'     => self::ACCESS_ALLOW,
171
+			),
172
+			PageCustomClose::class               => array(
173
+				self::MAIN => self::ACCESS_ALLOW,
174
+			),
175
+			PageComment::class                   => array(
176
+				self::MAIN => self::ACCESS_ALLOW,
177
+			),
178
+			PageCloseRequest::class              => array(
179
+				self::MAIN => self::ACCESS_ALLOW,
180
+			),
181
+			PageCreateRequest::class             => array(
182
+				self::MAIN => self::ACCESS_ALLOW,
183
+			),
184
+			PageDeferRequest::class              => array(
185
+				self::MAIN => self::ACCESS_ALLOW,
186
+			),
187
+			PageDropRequest::class               => array(
188
+				self::MAIN => self::ACCESS_ALLOW,
189
+			),
190
+			PageReservation::class               => array(
191
+				self::MAIN => self::ACCESS_ALLOW,
192
+			),
193
+			PageSendToUser::class                => array(
194
+				self::MAIN => self::ACCESS_ALLOW,
195
+			),
196
+			PageBreakReservation::class          => array(
197
+				self::MAIN => self::ACCESS_ALLOW,
198
+			),
199
+			PageJobQueue::class                  => array(
200
+				self::MAIN => self::ACCESS_ALLOW,
201
+				'view'     => self::ACCESS_ALLOW,
202
+				'all'      => self::ACCESS_ALLOW,
203
+			),
204
+			'RequestCreation'                    => array(
205
+				User::CREATION_MANUAL => self::ACCESS_ALLOW,
206
+			),
207
+			'GlobalInfo'                         => array(
208
+				'viewSiteNotice' => self::ACCESS_ALLOW,
209
+				'viewOnlineUsers' => self::ACCESS_ALLOW,
210
+			),
211
+		),
212
+		'admin'             => array(
213
+			'_description'                       => 'A tool administrator.',
214
+			'_editableBy'                        => array('admin', 'toolRoot'),
215
+			'_childRoles'                        => array(
216
+				'user',
217
+				'requestAdminTools',
218
+			),
219
+			PageEmailManagement::class           => array(
220
+				'edit'   => self::ACCESS_ALLOW,
221
+				'create' => self::ACCESS_ALLOW,
222
+			),
223
+			PageSiteNotice::class                => array(
224
+				self::MAIN => self::ACCESS_ALLOW,
225
+			),
226
+			PageUserManagement::class            => array(
227
+				self::MAIN  => self::ACCESS_ALLOW,
228
+				'approve'   => self::ACCESS_ALLOW,
229
+				'decline'   => self::ACCESS_ALLOW,
230
+				'rename'    => self::ACCESS_ALLOW,
231
+				'editUser'  => self::ACCESS_ALLOW,
232
+				'suspend'   => self::ACCESS_ALLOW,
233
+				'editRoles' => self::ACCESS_ALLOW,
234
+			),
235
+			PageWelcomeTemplateManagement::class => array(
236
+				'edit'   => self::ACCESS_ALLOW,
237
+				'delete' => self::ACCESS_ALLOW,
238
+				'add'    => self::ACCESS_ALLOW,
239
+			),
240
+			PageJobQueue::class                  => array(
241
+				'acknowledge' => self::ACCESS_ALLOW,
242
+				'requeue'     => self::ACCESS_ALLOW,
243
+			),
244
+		),
245
+		'checkuser'         => array(
246
+			'_description'            => 'A user with CheckUser access',
247
+			'_editableBy'             => array('checkuser', 'toolRoot'),
248
+			'_childRoles'             => array(
249
+				'user',
250
+				'requestAdminTools',
251
+			),
252
+			PageUserManagement::class => array(
253
+				self::MAIN  => self::ACCESS_ALLOW,
254
+				'suspend'   => self::ACCESS_ALLOW,
255
+				'editRoles' => self::ACCESS_ALLOW,
256
+			),
257
+			'RequestData'             => array(
258
+				'seeUserAgentData' => self::ACCESS_ALLOW,
259
+			),
260
+		),
261
+		'toolRoot'          => array(
262
+			'_description' => 'A user with shell access to the servers running the tool',
263
+			'_editableBy'  => array('toolRoot'),
264
+			'_childRoles'  => array(
265
+				'admin',
266
+			),
267
+			PageMultiFactor::class => array(
268
+				'enableU2F'         => self::ACCESS_ALLOW,
269
+				'disableU2F'        => self::ACCESS_ALLOW,
270
+			)
271
+		),
272
+		'botCreation'       => array(
273
+			'_description'    => 'A user allowed to use the bot to perform account creations',
274
+			'_editableBy'     => array('admin', 'toolRoot'),
275
+			'_childRoles'     => array(),
276
+			'RequestCreation' => array(
277
+				User::CREATION_BOT => self::ACCESS_ALLOW,
278
+			),
279
+		),
280
+		'oauthCreation'       => array(
281
+			'_description'    => 'A user allowed to use the OAuth to perform account creations',
282
+			'_editableBy'     => array('admin', 'toolRoot'),
283
+			'_childRoles'     => array(),
284
+			'RequestCreation'                    => array(
285
+				User::CREATION_OAUTH  => self::ACCESS_ALLOW,
286
+			),
287
+		),
288 288
 
289 289
 
290
-        // Child roles go below this point
291
-        'publicStats'       => array(
292
-            '_hidden'               => true,
293
-            StatsUsers::class       => array(
294
-                self::MAIN => self::ACCESS_ALLOW,
295
-                'detail'   => self::ACCESS_ALLOW,
296
-            ),
297
-            StatsTopCreators::class => array(
298
-                self::MAIN => self::ACCESS_ALLOW,
299
-            ),
300
-        ),
301
-        'internalStats'     => array(
302
-            '_hidden'                    => true,
303
-            StatsMain::class             => array(
304
-                self::MAIN => self::ACCESS_ALLOW,
305
-            ),
306
-            StatsFastCloses::class       => array(
307
-                self::MAIN => self::ACCESS_ALLOW,
308
-            ),
309
-            StatsInactiveUsers::class    => array(
310
-                self::MAIN => self::ACCESS_ALLOW,
311
-            ),
312
-            StatsMonthlyStats::class     => array(
313
-                self::MAIN => self::ACCESS_ALLOW,
314
-            ),
315
-            StatsReservedRequests::class => array(
316
-                self::MAIN => self::ACCESS_ALLOW,
317
-            ),
318
-            StatsTemplateStats::class    => array(
319
-                self::MAIN => self::ACCESS_ALLOW,
320
-            ),
321
-        ),
322
-        'requestAdminTools' => array(
323
-            '_hidden'                   => true,
324
-            PageBan::class              => array(
325
-                self::MAIN => self::ACCESS_ALLOW,
326
-                'set'      => self::ACCESS_ALLOW,
327
-                'remove'   => self::ACCESS_ALLOW,
328
-            ),
329
-            PageEditComment::class      => array(
330
-                'editOthers' => self::ACCESS_ALLOW,
331
-            ),
332
-            PageBreakReservation::class => array(
333
-                'force' => self::ACCESS_ALLOW,
334
-            ),
335
-            PageCustomClose::class      => array(
336
-                'skipCcMailingList' => self::ACCESS_ALLOW,
337
-            ),
338
-            'RequestData'               => array(
339
-                'reopenOldRequest'      => self::ACCESS_ALLOW,
340
-                'alwaysSeePrivateData'  => self::ACCESS_ALLOW,
341
-                'alwaysSeeHash'         => self::ACCESS_ALLOW,
342
-                'seeRestrictedComments' => self::ACCESS_ALLOW,
343
-            ),
344
-        ),
345
-    );
346
-    /** @var array
347
-     * List of roles which are *exempt* from the identification requirements
348
-     *
349
-     * Think twice about adding roles to this list.
350
-     *
351
-     * @category Security-Critical
352
-     */
353
-    private $identificationExempt = array('public', 'loggedIn');
290
+		// Child roles go below this point
291
+		'publicStats'       => array(
292
+			'_hidden'               => true,
293
+			StatsUsers::class       => array(
294
+				self::MAIN => self::ACCESS_ALLOW,
295
+				'detail'   => self::ACCESS_ALLOW,
296
+			),
297
+			StatsTopCreators::class => array(
298
+				self::MAIN => self::ACCESS_ALLOW,
299
+			),
300
+		),
301
+		'internalStats'     => array(
302
+			'_hidden'                    => true,
303
+			StatsMain::class             => array(
304
+				self::MAIN => self::ACCESS_ALLOW,
305
+			),
306
+			StatsFastCloses::class       => array(
307
+				self::MAIN => self::ACCESS_ALLOW,
308
+			),
309
+			StatsInactiveUsers::class    => array(
310
+				self::MAIN => self::ACCESS_ALLOW,
311
+			),
312
+			StatsMonthlyStats::class     => array(
313
+				self::MAIN => self::ACCESS_ALLOW,
314
+			),
315
+			StatsReservedRequests::class => array(
316
+				self::MAIN => self::ACCESS_ALLOW,
317
+			),
318
+			StatsTemplateStats::class    => array(
319
+				self::MAIN => self::ACCESS_ALLOW,
320
+			),
321
+		),
322
+		'requestAdminTools' => array(
323
+			'_hidden'                   => true,
324
+			PageBan::class              => array(
325
+				self::MAIN => self::ACCESS_ALLOW,
326
+				'set'      => self::ACCESS_ALLOW,
327
+				'remove'   => self::ACCESS_ALLOW,
328
+			),
329
+			PageEditComment::class      => array(
330
+				'editOthers' => self::ACCESS_ALLOW,
331
+			),
332
+			PageBreakReservation::class => array(
333
+				'force' => self::ACCESS_ALLOW,
334
+			),
335
+			PageCustomClose::class      => array(
336
+				'skipCcMailingList' => self::ACCESS_ALLOW,
337
+			),
338
+			'RequestData'               => array(
339
+				'reopenOldRequest'      => self::ACCESS_ALLOW,
340
+				'alwaysSeePrivateData'  => self::ACCESS_ALLOW,
341
+				'alwaysSeeHash'         => self::ACCESS_ALLOW,
342
+				'seeRestrictedComments' => self::ACCESS_ALLOW,
343
+			),
344
+		),
345
+	);
346
+	/** @var array
347
+	 * List of roles which are *exempt* from the identification requirements
348
+	 *
349
+	 * Think twice about adding roles to this list.
350
+	 *
351
+	 * @category Security-Critical
352
+	 */
353
+	private $identificationExempt = array('public', 'loggedIn');
354 354
 
355
-    /**
356
-     * RoleConfiguration constructor.
357
-     *
358
-     * @param array $roleConfig           Set to non-null to override the default configuration.
359
-     * @param array $identificationExempt Set to non-null to override the default configuration.
360
-     */
361
-    public function __construct(array $roleConfig = null, array $identificationExempt = null)
362
-    {
363
-        if ($roleConfig !== null) {
364
-            $this->roleConfig = $roleConfig;
365
-        }
355
+	/**
356
+	 * RoleConfiguration constructor.
357
+	 *
358
+	 * @param array $roleConfig           Set to non-null to override the default configuration.
359
+	 * @param array $identificationExempt Set to non-null to override the default configuration.
360
+	 */
361
+	public function __construct(array $roleConfig = null, array $identificationExempt = null)
362
+	{
363
+		if ($roleConfig !== null) {
364
+			$this->roleConfig = $roleConfig;
365
+		}
366 366
 
367
-        if ($identificationExempt !== null) {
368
-            $this->identificationExempt = $identificationExempt;
369
-        }
370
-    }
367
+		if ($identificationExempt !== null) {
368
+			$this->identificationExempt = $identificationExempt;
369
+		}
370
+	}
371 371
 
372
-    /**
373
-     * @param array $roles The roles to check
374
-     *
375
-     * @return array
376
-     */
377
-    public function getApplicableRoles(array $roles)
378
-    {
379
-        $available = array();
372
+	/**
373
+	 * @param array $roles The roles to check
374
+	 *
375
+	 * @return array
376
+	 */
377
+	public function getApplicableRoles(array $roles)
378
+	{
379
+		$available = array();
380 380
 
381
-        foreach ($roles as $role) {
382
-            if (!isset($this->roleConfig[$role])) {
383
-                // wat
384
-                continue;
385
-            }
381
+		foreach ($roles as $role) {
382
+			if (!isset($this->roleConfig[$role])) {
383
+				// wat
384
+				continue;
385
+			}
386 386
 
387
-            $available[$role] = $this->roleConfig[$role];
387
+			$available[$role] = $this->roleConfig[$role];
388 388
 
389
-            if (isset($available[$role]['_childRoles'])) {
390
-                $childRoles = $this->getApplicableRoles($available[$role]['_childRoles']);
391
-                $available = array_merge($available, $childRoles);
389
+			if (isset($available[$role]['_childRoles'])) {
390
+				$childRoles = $this->getApplicableRoles($available[$role]['_childRoles']);
391
+				$available = array_merge($available, $childRoles);
392 392
 
393
-                unset($available[$role]['_childRoles']);
394
-            }
393
+				unset($available[$role]['_childRoles']);
394
+			}
395 395
 
396
-            foreach (array('_hidden', '_editableBy', '_description') as $item) {
397
-                if (isset($available[$role][$item])) {
398
-                    unset($available[$role][$item]);
399
-                }
400
-            }
401
-        }
396
+			foreach (array('_hidden', '_editableBy', '_description') as $item) {
397
+				if (isset($available[$role][$item])) {
398
+					unset($available[$role][$item]);
399
+				}
400
+			}
401
+		}
402 402
 
403
-        return $available;
404
-    }
403
+		return $available;
404
+	}
405 405
 
406
-    public function getAvailableRoles()
407
-    {
408
-        $possible = array_diff(array_keys($this->roleConfig), array('public', 'loggedIn'));
406
+	public function getAvailableRoles()
407
+	{
408
+		$possible = array_diff(array_keys($this->roleConfig), array('public', 'loggedIn'));
409 409
 
410
-        $actual = array();
410
+		$actual = array();
411 411
 
412
-        foreach ($possible as $role) {
413
-            if (!isset($this->roleConfig[$role]['_hidden'])) {
414
-                $actual[$role] = array(
415
-                    'description' => $this->roleConfig[$role]['_description'],
416
-                    'editableBy'  => $this->roleConfig[$role]['_editableBy'],
417
-                );
418
-            }
419
-        }
412
+		foreach ($possible as $role) {
413
+			if (!isset($this->roleConfig[$role]['_hidden'])) {
414
+				$actual[$role] = array(
415
+					'description' => $this->roleConfig[$role]['_description'],
416
+					'editableBy'  => $this->roleConfig[$role]['_editableBy'],
417
+				);
418
+			}
419
+		}
420 420
 
421
-        return $actual;
422
-    }
421
+		return $actual;
422
+	}
423 423
 
424
-    /**
425
-     * @param string $role
426
-     *
427
-     * @return bool
428
-     */
429
-    public function roleNeedsIdentification($role)
430
-    {
431
-        if (in_array($role, $this->identificationExempt)) {
432
-            return false;
433
-        }
424
+	/**
425
+	 * @param string $role
426
+	 *
427
+	 * @return bool
428
+	 */
429
+	public function roleNeedsIdentification($role)
430
+	{
431
+		if (in_array($role, $this->identificationExempt)) {
432
+			return false;
433
+		}
434 434
 
435
-        return true;
436
-    }
435
+		return true;
436
+	}
437 437
 }
Please login to merge, or discard this patch.
includes/Security/AuthenticationManager.php 1 patch
Indentation   +56 added lines, -56 removed lines patch added patch discarded remove patch
@@ -22,67 +22,67 @@
 block discarded – undo
22 22
 
23 23
 class AuthenticationManager
24 24
 {
25
-    const AUTH_OK = 1;
26
-    const AUTH_FAIL = 2;
27
-    const AUTH_REQUIRE_NEXT_STAGE = 3;
28
-    private $typeMap = array();
29
-    /**
30
-     * @var PdoDatabase
31
-     */
32
-    private $database;
25
+	const AUTH_OK = 1;
26
+	const AUTH_FAIL = 2;
27
+	const AUTH_REQUIRE_NEXT_STAGE = 3;
28
+	private $typeMap = array();
29
+	/**
30
+	 * @var PdoDatabase
31
+	 */
32
+	private $database;
33 33
 
34
-    /**
35
-     * AuthenticationManager constructor.
36
-     *
37
-     * @param PdoDatabase       $database
38
-     * @param SiteConfiguration $siteConfiguration
39
-     * @param HttpHelper        $httpHelper
40
-     */
41
-    public function __construct(PdoDatabase $database, SiteConfiguration $siteConfiguration, HttpHelper $httpHelper)
42
-    {
43
-        // setup providers
44
-        // note on type map: this *must* be the value in the database, as this is what it maps.
45
-        $this->typeMap['password'] = new PasswordCredentialProvider($database, $siteConfiguration);
46
-        $this->typeMap['yubikeyotp'] = new YubikeyOtpCredentialProvider($database, $siteConfiguration, $httpHelper);
47
-        $this->typeMap['totp'] = new TotpCredentialProvider($database, $siteConfiguration);
48
-        $this->typeMap['scratch'] = new ScratchTokenCredentialProvider($database, $siteConfiguration);
49
-        $this->typeMap['u2f'] = new U2FCredentialProvider($database, $siteConfiguration);
50
-        $this->database = $database;
51
-    }
34
+	/**
35
+	 * AuthenticationManager constructor.
36
+	 *
37
+	 * @param PdoDatabase       $database
38
+	 * @param SiteConfiguration $siteConfiguration
39
+	 * @param HttpHelper        $httpHelper
40
+	 */
41
+	public function __construct(PdoDatabase $database, SiteConfiguration $siteConfiguration, HttpHelper $httpHelper)
42
+	{
43
+		// setup providers
44
+		// note on type map: this *must* be the value in the database, as this is what it maps.
45
+		$this->typeMap['password'] = new PasswordCredentialProvider($database, $siteConfiguration);
46
+		$this->typeMap['yubikeyotp'] = new YubikeyOtpCredentialProvider($database, $siteConfiguration, $httpHelper);
47
+		$this->typeMap['totp'] = new TotpCredentialProvider($database, $siteConfiguration);
48
+		$this->typeMap['scratch'] = new ScratchTokenCredentialProvider($database, $siteConfiguration);
49
+		$this->typeMap['u2f'] = new U2FCredentialProvider($database, $siteConfiguration);
50
+		$this->database = $database;
51
+	}
52 52
 
53
-    public function authenticate(User $user, $data, $stage)
54
-    {
55
-        $sql = 'SELECT type FROM credential WHERE user = :user AND factor = :stage AND disabled = 0 ORDER BY priority ASC';
56
-        $statement = $this->database->prepare($sql);
57
-        $statement->execute(array(':user' => $user->getId(), ':stage' => $stage));
58
-        $options = $statement->fetchAll(PDO::FETCH_COLUMN);
53
+	public function authenticate(User $user, $data, $stage)
54
+	{
55
+		$sql = 'SELECT type FROM credential WHERE user = :user AND factor = :stage AND disabled = 0 ORDER BY priority ASC';
56
+		$statement = $this->database->prepare($sql);
57
+		$statement->execute(array(':user' => $user->getId(), ':stage' => $stage));
58
+		$options = $statement->fetchAll(PDO::FETCH_COLUMN);
59 59
 
60
-        $sql = 'SELECT count(DISTINCT factor) FROM credential WHERE user = :user AND factor > :stage AND disabled = 0 AND type <> :scratch';
61
-        $statement = $this->database->prepare($sql);
62
-        $statement->execute(array(':user' => $user->getId(), ':stage' => $stage, ':scratch' => 'scratch'));
63
-        $requiredFactors = $statement->fetchColumn();
60
+		$sql = 'SELECT count(DISTINCT factor) FROM credential WHERE user = :user AND factor > :stage AND disabled = 0 AND type <> :scratch';
61
+		$statement = $this->database->prepare($sql);
62
+		$statement->execute(array(':user' => $user->getId(), ':stage' => $stage, ':scratch' => 'scratch'));
63
+		$requiredFactors = $statement->fetchColumn();
64 64
 
65
-        // prep the correct OK response based on how many factors are ahead of this one
66
-        $success = self::AUTH_OK;
67
-        if ($requiredFactors > 0) {
68
-            $success = self::AUTH_REQUIRE_NEXT_STAGE;
69
-        }
65
+		// prep the correct OK response based on how many factors are ahead of this one
66
+		$success = self::AUTH_OK;
67
+		if ($requiredFactors > 0) {
68
+			$success = self::AUTH_REQUIRE_NEXT_STAGE;
69
+		}
70 70
 
71
-        foreach ($options as $type) {
72
-            if (!isset($this->typeMap[$type])) {
73
-                // does this type have a credentialProvider registered?
74
-                continue;
75
-            }
71
+		foreach ($options as $type) {
72
+			if (!isset($this->typeMap[$type])) {
73
+				// does this type have a credentialProvider registered?
74
+				continue;
75
+			}
76 76
 
77
-            /** @var ICredentialProvider $credentialProvider */
78
-            $credentialProvider = $this->typeMap[$type];
79
-            if ($credentialProvider->authenticate($user, $data)) {
80
-                return $success;
81
-            }
82
-        }
77
+			/** @var ICredentialProvider $credentialProvider */
78
+			$credentialProvider = $this->typeMap[$type];
79
+			if ($credentialProvider->authenticate($user, $data)) {
80
+				return $success;
81
+			}
82
+		}
83 83
 
84
-        // We've iterated over all the available providers for this stage.
85
-        // They all hate you.
86
-        return self::AUTH_FAIL;
87
-    }
84
+		// We've iterated over all the available providers for this stage.
85
+		// They all hate you.
86
+		return self::AUTH_FAIL;
87
+	}
88 88
 }
89 89
\ No newline at end of file
Please login to merge, or discard this patch.
includes/Providers/GlobalState/GlobalStateProvider.php 1 patch
Indentation   +35 added lines, -35 removed lines patch added patch discarded remove patch
@@ -18,43 +18,43 @@
 block discarded – undo
18 18
  */
19 19
 class GlobalStateProvider implements IGlobalStateProvider
20 20
 {
21
-    /**
22
-     * @return array
23
-     */
24
-    public function &getServerSuperGlobal()
25
-    {
26
-        return $_SERVER;
27
-    }
21
+	/**
22
+	 * @return array
23
+	 */
24
+	public function &getServerSuperGlobal()
25
+	{
26
+		return $_SERVER;
27
+	}
28 28
 
29
-    /**
30
-     * @return array
31
-     */
32
-    public function &getGetSuperGlobal()
33
-    {
34
-        return $_GET;
35
-    }
29
+	/**
30
+	 * @return array
31
+	 */
32
+	public function &getGetSuperGlobal()
33
+	{
34
+		return $_GET;
35
+	}
36 36
 
37
-    /**
38
-     * @return array
39
-     */
40
-    public function &getPostSuperGlobal()
41
-    {
42
-        return $_POST;
43
-    }
37
+	/**
38
+	 * @return array
39
+	 */
40
+	public function &getPostSuperGlobal()
41
+	{
42
+		return $_POST;
43
+	}
44 44
 
45
-    /**
46
-     * @return array
47
-     */
48
-    public function &getSessionSuperGlobal()
49
-    {
50
-        return $_SESSION;
51
-    }
45
+	/**
46
+	 * @return array
47
+	 */
48
+	public function &getSessionSuperGlobal()
49
+	{
50
+		return $_SESSION;
51
+	}
52 52
 
53
-    /**
54
-     * @return array
55
-     */
56
-    public function &getCookieSuperGlobal()
57
-    {
58
-        return $_COOKIE;
59
-    }
53
+	/**
54
+	 * @return array
55
+	 */
56
+	public function &getCookieSuperGlobal()
57
+	{
58
+		return $_COOKIE;
59
+	}
60 60
 }
61 61
\ No newline at end of file
Please login to merge, or discard this patch.