Completed
Push — master ( 19d552...6b730b )
by Morris
21:07 queued 10:33
created
lib/private/Authentication/Token/Manager.php 1 patch
Indentation   +209 added lines, -209 removed lines patch added patch discarded remove patch
@@ -28,215 +28,215 @@
 block discarded – undo
28 28
 
29 29
 class Manager implements IProvider {
30 30
 
31
-	/** @var DefaultTokenProvider */
32
-	private $defaultTokenProvider;
33
-
34
-	/** @var PublicKeyTokenProvider */
35
-	private $publicKeyTokenProvider;
36
-
37
-	public function __construct(DefaultTokenProvider $defaultTokenProvider, PublicKeyTokenProvider $publicKeyTokenProvider) {
38
-		$this->defaultTokenProvider = $defaultTokenProvider;
39
-		$this->publicKeyTokenProvider = $publicKeyTokenProvider;
40
-	}
41
-
42
-	/**
43
-	 * Create and persist a new token
44
-	 *
45
-	 * @param string $token
46
-	 * @param string $uid
47
-	 * @param string $loginName
48
-	 * @param string|null $password
49
-	 * @param string $name
50
-	 * @param int $type token type
51
-	 * @param int $remember whether the session token should be used for remember-me
52
-	 * @return IToken
53
-	 */
54
-	public function generateToken(string $token,
55
-								  string $uid,
56
-								  string $loginName,
57
-								  $password,
58
-								  string $name,
59
-								  int $type = IToken::TEMPORARY_TOKEN,
60
-								  int $remember = IToken::DO_NOT_REMEMBER): IToken {
61
-		return $this->publicKeyTokenProvider->generateToken(
62
-			$token,
63
-			$uid,
64
-			$loginName,
65
-			$password,
66
-			$name,
67
-			$type,
68
-			$remember
69
-		);
70
-	}
71
-
72
-	/**
73
-	 * Save the updated token
74
-	 *
75
-	 * @param IToken $token
76
-	 * @throws InvalidTokenException
77
-	 */
78
-	public function updateToken(IToken $token) {
79
-		$provider = $this->getProvider($token);
80
-		$provider->updateToken($token);
81
-	}
82
-
83
-	/**
84
-	 * Update token activity timestamp
85
-	 *
86
-	 * @throws InvalidTokenException
87
-	 * @param IToken $token
88
-	 */
89
-	public function updateTokenActivity(IToken $token) {
90
-		$provider = $this->getProvider($token);
91
-		$provider->updateTokenActivity($token);
92
-	}
93
-
94
-	/**
95
-	 * @param string $uid
96
-	 * @return IToken[]
97
-	 */
98
-	public function getTokenByUser(string $uid): array {
99
-		$old = $this->defaultTokenProvider->getTokenByUser($uid);
100
-		$new = $this->publicKeyTokenProvider->getTokenByUser($uid);
101
-
102
-		return array_merge($old, $new);
103
-	}
104
-
105
-	/**
106
-	 * Get a token by token
107
-	 *
108
-	 * @param string $tokenId
109
-	 * @throws InvalidTokenException
110
-	 * @return IToken
111
-	 */
112
-	public function getToken(string $tokenId): IToken {
113
-		try {
114
-			return $this->publicKeyTokenProvider->getToken($tokenId);
115
-		} catch (InvalidTokenException $e) {
116
-			// No worries we try to convert it to a PublicKey Token
117
-		}
118
-
119
-		//Convert!
120
-		$token = $this->defaultTokenProvider->getToken($tokenId);
121
-
122
-		try {
123
-			$password = $this->defaultTokenProvider->getPassword($token, $tokenId);
124
-		} catch (PasswordlessTokenException $e) {
125
-			$password = null;
126
-		}
127
-
128
-		return $this->publicKeyTokenProvider->convertToken($token, $tokenId, $password);
129
-	}
130
-
131
-	/**
132
-	 * Get a token by token id
133
-	 *
134
-	 * @param int $tokenId
135
-	 * @throws InvalidTokenException
136
-	 * @return IToken
137
-	 */
138
-	public function getTokenById(int $tokenId): IToken {
139
-		try {
140
-			return $this->publicKeyTokenProvider->getTokenById($tokenId);
141
-		} catch (InvalidTokenException $e) {
142
-			return $this->defaultTokenProvider->getTokenById($tokenId);
143
-		}
144
-	}
145
-
146
-	/**
147
-	 * @param string $oldSessionId
148
-	 * @param string $sessionId
149
-	 * @throws InvalidTokenException
150
-	 */
151
-	public function renewSessionToken(string $oldSessionId, string $sessionId) {
152
-		try {
153
-			$this->publicKeyTokenProvider->renewSessionToken($oldSessionId, $sessionId);
154
-		} catch (InvalidTokenException $e) {
155
-			$this->defaultTokenProvider->renewSessionToken($oldSessionId, $sessionId);
156
-		}
157
-	}
158
-
159
-	/**
160
-	 * @param IToken $savedToken
161
-	 * @param string $tokenId session token
162
-	 * @throws InvalidTokenException
163
-	 * @throws PasswordlessTokenException
164
-	 * @return string
165
-	 */
166
-	public function getPassword(IToken $savedToken, string $tokenId): string {
167
-		$provider = $this->getProvider($savedToken);
168
-		return $provider->getPassword($savedToken, $tokenId);
169
-	}
170
-
171
-	public function setPassword(IToken $token, string $tokenId, string $password) {
172
-		$provider = $this->getProvider($token);
173
-		$provider->setPassword($token, $tokenId, $password);
174
-	}
175
-
176
-	public function invalidateToken(string $token) {
177
-		$this->defaultTokenProvider->invalidateToken($token);
178
-		$this->publicKeyTokenProvider->invalidateToken($token);
179
-	}
180
-
181
-	public function invalidateTokenById(string $uid, int $id) {
182
-		$this->defaultTokenProvider->invalidateTokenById($uid, $id);
183
-		$this->publicKeyTokenProvider->invalidateTokenById($uid, $id);
184
-	}
185
-
186
-	public function invalidateOldTokens() {
187
-		$this->defaultTokenProvider->invalidateOldTokens();
188
-		$this->publicKeyTokenProvider->invalidateOldTokens();
189
-	}
190
-
191
-	/**
192
-	 * @param IToken $token
193
-	 * @param string $oldTokenId
194
-	 * @param string $newTokenId
195
-	 * @return IToken
196
-	 * @throws InvalidTokenException
197
-	 */
198
-	public function rotate(IToken $token, string $oldTokenId, string $newTokenId): IToken {
199
-		if ($token instanceof DefaultToken) {
200
-			try {
201
-				$password = $this->defaultTokenProvider->getPassword($token, $oldTokenId);
202
-			} catch (PasswordlessTokenException $e) {
203
-				$password = null;
204
-			}
205
-
206
-			return $this->publicKeyTokenProvider->convertToken($token, $newTokenId, $password);
207
-		}
208
-
209
-		if ($token instanceof PublicKeyToken) {
210
-			return $this->publicKeyTokenProvider->rotate($token, $oldTokenId, $newTokenId);
211
-		}
212
-
213
-		throw new InvalidTokenException();
214
-	}
215
-
216
-	/**
217
-	 * @param IToken $token
218
-	 * @return IProvider
219
-	 * @throws InvalidTokenException
220
-	 */
221
-	private function getProvider(IToken $token): IProvider {
222
-		if ($token instanceof DefaultToken) {
223
-			return $this->defaultTokenProvider;
224
-		}
225
-		if ($token instanceof PublicKeyToken) {
226
-			return $this->publicKeyTokenProvider;
227
-		}
228
-		throw new InvalidTokenException();
229
-	}
230
-
231
-
232
-	public function markPasswordInvalid(IToken $token, string $tokenId) {
233
-		$this->getProvider($token)->markPasswordInvalid($token, $tokenId);
234
-	}
235
-
236
-	public function updatePasswords(string $uid, string $password) {
237
-		$this->defaultTokenProvider->updatePasswords($uid, $password);
238
-		$this->publicKeyTokenProvider->updatePasswords($uid, $password);
239
-	}
31
+    /** @var DefaultTokenProvider */
32
+    private $defaultTokenProvider;
33
+
34
+    /** @var PublicKeyTokenProvider */
35
+    private $publicKeyTokenProvider;
36
+
37
+    public function __construct(DefaultTokenProvider $defaultTokenProvider, PublicKeyTokenProvider $publicKeyTokenProvider) {
38
+        $this->defaultTokenProvider = $defaultTokenProvider;
39
+        $this->publicKeyTokenProvider = $publicKeyTokenProvider;
40
+    }
41
+
42
+    /**
43
+     * Create and persist a new token
44
+     *
45
+     * @param string $token
46
+     * @param string $uid
47
+     * @param string $loginName
48
+     * @param string|null $password
49
+     * @param string $name
50
+     * @param int $type token type
51
+     * @param int $remember whether the session token should be used for remember-me
52
+     * @return IToken
53
+     */
54
+    public function generateToken(string $token,
55
+                                    string $uid,
56
+                                    string $loginName,
57
+                                    $password,
58
+                                    string $name,
59
+                                    int $type = IToken::TEMPORARY_TOKEN,
60
+                                    int $remember = IToken::DO_NOT_REMEMBER): IToken {
61
+        return $this->publicKeyTokenProvider->generateToken(
62
+            $token,
63
+            $uid,
64
+            $loginName,
65
+            $password,
66
+            $name,
67
+            $type,
68
+            $remember
69
+        );
70
+    }
71
+
72
+    /**
73
+     * Save the updated token
74
+     *
75
+     * @param IToken $token
76
+     * @throws InvalidTokenException
77
+     */
78
+    public function updateToken(IToken $token) {
79
+        $provider = $this->getProvider($token);
80
+        $provider->updateToken($token);
81
+    }
82
+
83
+    /**
84
+     * Update token activity timestamp
85
+     *
86
+     * @throws InvalidTokenException
87
+     * @param IToken $token
88
+     */
89
+    public function updateTokenActivity(IToken $token) {
90
+        $provider = $this->getProvider($token);
91
+        $provider->updateTokenActivity($token);
92
+    }
93
+
94
+    /**
95
+     * @param string $uid
96
+     * @return IToken[]
97
+     */
98
+    public function getTokenByUser(string $uid): array {
99
+        $old = $this->defaultTokenProvider->getTokenByUser($uid);
100
+        $new = $this->publicKeyTokenProvider->getTokenByUser($uid);
101
+
102
+        return array_merge($old, $new);
103
+    }
104
+
105
+    /**
106
+     * Get a token by token
107
+     *
108
+     * @param string $tokenId
109
+     * @throws InvalidTokenException
110
+     * @return IToken
111
+     */
112
+    public function getToken(string $tokenId): IToken {
113
+        try {
114
+            return $this->publicKeyTokenProvider->getToken($tokenId);
115
+        } catch (InvalidTokenException $e) {
116
+            // No worries we try to convert it to a PublicKey Token
117
+        }
118
+
119
+        //Convert!
120
+        $token = $this->defaultTokenProvider->getToken($tokenId);
121
+
122
+        try {
123
+            $password = $this->defaultTokenProvider->getPassword($token, $tokenId);
124
+        } catch (PasswordlessTokenException $e) {
125
+            $password = null;
126
+        }
127
+
128
+        return $this->publicKeyTokenProvider->convertToken($token, $tokenId, $password);
129
+    }
130
+
131
+    /**
132
+     * Get a token by token id
133
+     *
134
+     * @param int $tokenId
135
+     * @throws InvalidTokenException
136
+     * @return IToken
137
+     */
138
+    public function getTokenById(int $tokenId): IToken {
139
+        try {
140
+            return $this->publicKeyTokenProvider->getTokenById($tokenId);
141
+        } catch (InvalidTokenException $e) {
142
+            return $this->defaultTokenProvider->getTokenById($tokenId);
143
+        }
144
+    }
145
+
146
+    /**
147
+     * @param string $oldSessionId
148
+     * @param string $sessionId
149
+     * @throws InvalidTokenException
150
+     */
151
+    public function renewSessionToken(string $oldSessionId, string $sessionId) {
152
+        try {
153
+            $this->publicKeyTokenProvider->renewSessionToken($oldSessionId, $sessionId);
154
+        } catch (InvalidTokenException $e) {
155
+            $this->defaultTokenProvider->renewSessionToken($oldSessionId, $sessionId);
156
+        }
157
+    }
158
+
159
+    /**
160
+     * @param IToken $savedToken
161
+     * @param string $tokenId session token
162
+     * @throws InvalidTokenException
163
+     * @throws PasswordlessTokenException
164
+     * @return string
165
+     */
166
+    public function getPassword(IToken $savedToken, string $tokenId): string {
167
+        $provider = $this->getProvider($savedToken);
168
+        return $provider->getPassword($savedToken, $tokenId);
169
+    }
170
+
171
+    public function setPassword(IToken $token, string $tokenId, string $password) {
172
+        $provider = $this->getProvider($token);
173
+        $provider->setPassword($token, $tokenId, $password);
174
+    }
175
+
176
+    public function invalidateToken(string $token) {
177
+        $this->defaultTokenProvider->invalidateToken($token);
178
+        $this->publicKeyTokenProvider->invalidateToken($token);
179
+    }
180
+
181
+    public function invalidateTokenById(string $uid, int $id) {
182
+        $this->defaultTokenProvider->invalidateTokenById($uid, $id);
183
+        $this->publicKeyTokenProvider->invalidateTokenById($uid, $id);
184
+    }
185
+
186
+    public function invalidateOldTokens() {
187
+        $this->defaultTokenProvider->invalidateOldTokens();
188
+        $this->publicKeyTokenProvider->invalidateOldTokens();
189
+    }
190
+
191
+    /**
192
+     * @param IToken $token
193
+     * @param string $oldTokenId
194
+     * @param string $newTokenId
195
+     * @return IToken
196
+     * @throws InvalidTokenException
197
+     */
198
+    public function rotate(IToken $token, string $oldTokenId, string $newTokenId): IToken {
199
+        if ($token instanceof DefaultToken) {
200
+            try {
201
+                $password = $this->defaultTokenProvider->getPassword($token, $oldTokenId);
202
+            } catch (PasswordlessTokenException $e) {
203
+                $password = null;
204
+            }
205
+
206
+            return $this->publicKeyTokenProvider->convertToken($token, $newTokenId, $password);
207
+        }
208
+
209
+        if ($token instanceof PublicKeyToken) {
210
+            return $this->publicKeyTokenProvider->rotate($token, $oldTokenId, $newTokenId);
211
+        }
212
+
213
+        throw new InvalidTokenException();
214
+    }
215
+
216
+    /**
217
+     * @param IToken $token
218
+     * @return IProvider
219
+     * @throws InvalidTokenException
220
+     */
221
+    private function getProvider(IToken $token): IProvider {
222
+        if ($token instanceof DefaultToken) {
223
+            return $this->defaultTokenProvider;
224
+        }
225
+        if ($token instanceof PublicKeyToken) {
226
+            return $this->publicKeyTokenProvider;
227
+        }
228
+        throw new InvalidTokenException();
229
+    }
230
+
231
+
232
+    public function markPasswordInvalid(IToken $token, string $tokenId) {
233
+        $this->getProvider($token)->markPasswordInvalid($token, $tokenId);
234
+    }
235
+
236
+    public function updatePasswords(string $uid, string $password) {
237
+        $this->defaultTokenProvider->updatePasswords($uid, $password);
238
+        $this->publicKeyTokenProvider->updatePasswords($uid, $password);
239
+    }
240 240
 
241 241
 
242 242
 }
Please login to merge, or discard this patch.
lib/private/Authentication/Token/PublicKeyToken.php 1 patch
Indentation   +176 added lines, -176 removed lines patch added patch discarded remove patch
@@ -47,180 +47,180 @@
 block discarded – undo
47 47
  */
48 48
 class PublicKeyToken extends Entity implements IToken {
49 49
 
50
-	const VERSION = 2;
51
-
52
-	/** @var string user UID */
53
-	protected $uid;
54
-
55
-	/** @var string login name used for generating the token */
56
-	protected $loginName;
57
-
58
-	/** @var string encrypted user password */
59
-	protected $password;
60
-
61
-	/** @var string token name (e.g. browser/OS) */
62
-	protected $name;
63
-
64
-	/** @var string */
65
-	protected $token;
66
-
67
-	/** @var int */
68
-	protected $type;
69
-
70
-	/** @var int */
71
-	protected $remember;
72
-
73
-	/** @var int */
74
-	protected $lastActivity;
75
-
76
-	/** @var int */
77
-	protected $lastCheck;
78
-
79
-	/** @var string */
80
-	protected $scope;
81
-
82
-	/** @var int */
83
-	protected $expires;
84
-
85
-	/** @var string */
86
-	protected $privateKey;
87
-
88
-	/** @var string */
89
-	protected $publicKey;
90
-
91
-	/** @var int */
92
-	protected $version;
93
-
94
-	/** @var bool */
95
-	protected $passwordInvalid;
96
-
97
-	public function __construct() {
98
-		$this->addType('uid', 'string');
99
-		$this->addType('loginName', 'string');
100
-		$this->addType('password', 'string');
101
-		$this->addType('name', 'string');
102
-		$this->addType('token', 'string');
103
-		$this->addType('type', 'int');
104
-		$this->addType('remember', 'int');
105
-		$this->addType('lastActivity', 'int');
106
-		$this->addType('lastCheck', 'int');
107
-		$this->addType('scope', 'string');
108
-		$this->addType('expires', 'int');
109
-		$this->addType('publicKey', 'string');
110
-		$this->addType('privateKey', 'string');
111
-		$this->addType('version', 'int');
112
-		$this->addType('passwordInvalid', 'bool');
113
-	}
114
-
115
-	public function getId(): int {
116
-		return $this->id;
117
-	}
118
-
119
-	public function getUID(): string {
120
-		return $this->uid;
121
-	}
122
-
123
-	/**
124
-	 * Get the login name used when generating the token
125
-	 *
126
-	 * @return string
127
-	 */
128
-	public function getLoginName(): string {
129
-		return parent::getLoginName();
130
-	}
131
-
132
-	/**
133
-	 * Get the (encrypted) login password
134
-	 *
135
-	 * @return string|null
136
-	 */
137
-	public function getPassword() {
138
-		return parent::getPassword();
139
-	}
140
-
141
-	public function jsonSerialize() {
142
-		return [
143
-			'id' => $this->id,
144
-			'name' => $this->name,
145
-			'lastActivity' => $this->lastActivity,
146
-			'type' => $this->type,
147
-			'scope' => $this->getScopeAsArray()
148
-		];
149
-	}
150
-
151
-	/**
152
-	 * Get the timestamp of the last password check
153
-	 *
154
-	 * @return int
155
-	 */
156
-	public function getLastCheck(): int {
157
-		return parent::getLastCheck();
158
-	}
159
-
160
-	/**
161
-	 * Get the timestamp of the last password check
162
-	 *
163
-	 * @param int $time
164
-	 */
165
-	public function setLastCheck(int $time) {
166
-		parent::setLastCheck($time);
167
-	}
168
-
169
-	public function getScope(): string {
170
-		$scope = parent::getScope();
171
-		if ($scope === null) {
172
-			return '';
173
-		}
174
-
175
-		return $scope;
176
-	}
177
-
178
-	public function getScopeAsArray(): array {
179
-		$scope = json_decode($this->getScope(), true);
180
-		if (!$scope) {
181
-			return [
182
-				'filesystem'=> true
183
-			];
184
-		}
185
-		return $scope;
186
-	}
187
-
188
-	public function setScope($scope) {
189
-		if (is_array($scope)) {
190
-			parent::setScope(json_encode($scope));
191
-		} else {
192
-			parent::setScope((string)$scope);
193
-		}
194
-	}
195
-
196
-	public function getName(): string {
197
-		return parent::getName();
198
-	}
199
-
200
-	public function getRemember(): int {
201
-		return parent::getRemember();
202
-	}
203
-
204
-	public function setToken(string $token) {
205
-		parent::setToken($token);
206
-	}
207
-
208
-	public function setPassword(string $password = null) {
209
-		parent::setPassword($password);
210
-	}
211
-
212
-	public function setExpires($expires) {
213
-		parent::setExpires($expires);
214
-	}
215
-
216
-	/**
217
-	 * @return int|null
218
-	 */
219
-	public function getExpires() {
220
-		return parent::getExpires();
221
-	}
222
-
223
-	public function setPasswordInvalid(bool $invalid) {
224
-		parent::setPasswordInvalid($invalid);
225
-	}
50
+    const VERSION = 2;
51
+
52
+    /** @var string user UID */
53
+    protected $uid;
54
+
55
+    /** @var string login name used for generating the token */
56
+    protected $loginName;
57
+
58
+    /** @var string encrypted user password */
59
+    protected $password;
60
+
61
+    /** @var string token name (e.g. browser/OS) */
62
+    protected $name;
63
+
64
+    /** @var string */
65
+    protected $token;
66
+
67
+    /** @var int */
68
+    protected $type;
69
+
70
+    /** @var int */
71
+    protected $remember;
72
+
73
+    /** @var int */
74
+    protected $lastActivity;
75
+
76
+    /** @var int */
77
+    protected $lastCheck;
78
+
79
+    /** @var string */
80
+    protected $scope;
81
+
82
+    /** @var int */
83
+    protected $expires;
84
+
85
+    /** @var string */
86
+    protected $privateKey;
87
+
88
+    /** @var string */
89
+    protected $publicKey;
90
+
91
+    /** @var int */
92
+    protected $version;
93
+
94
+    /** @var bool */
95
+    protected $passwordInvalid;
96
+
97
+    public function __construct() {
98
+        $this->addType('uid', 'string');
99
+        $this->addType('loginName', 'string');
100
+        $this->addType('password', 'string');
101
+        $this->addType('name', 'string');
102
+        $this->addType('token', 'string');
103
+        $this->addType('type', 'int');
104
+        $this->addType('remember', 'int');
105
+        $this->addType('lastActivity', 'int');
106
+        $this->addType('lastCheck', 'int');
107
+        $this->addType('scope', 'string');
108
+        $this->addType('expires', 'int');
109
+        $this->addType('publicKey', 'string');
110
+        $this->addType('privateKey', 'string');
111
+        $this->addType('version', 'int');
112
+        $this->addType('passwordInvalid', 'bool');
113
+    }
114
+
115
+    public function getId(): int {
116
+        return $this->id;
117
+    }
118
+
119
+    public function getUID(): string {
120
+        return $this->uid;
121
+    }
122
+
123
+    /**
124
+     * Get the login name used when generating the token
125
+     *
126
+     * @return string
127
+     */
128
+    public function getLoginName(): string {
129
+        return parent::getLoginName();
130
+    }
131
+
132
+    /**
133
+     * Get the (encrypted) login password
134
+     *
135
+     * @return string|null
136
+     */
137
+    public function getPassword() {
138
+        return parent::getPassword();
139
+    }
140
+
141
+    public function jsonSerialize() {
142
+        return [
143
+            'id' => $this->id,
144
+            'name' => $this->name,
145
+            'lastActivity' => $this->lastActivity,
146
+            'type' => $this->type,
147
+            'scope' => $this->getScopeAsArray()
148
+        ];
149
+    }
150
+
151
+    /**
152
+     * Get the timestamp of the last password check
153
+     *
154
+     * @return int
155
+     */
156
+    public function getLastCheck(): int {
157
+        return parent::getLastCheck();
158
+    }
159
+
160
+    /**
161
+     * Get the timestamp of the last password check
162
+     *
163
+     * @param int $time
164
+     */
165
+    public function setLastCheck(int $time) {
166
+        parent::setLastCheck($time);
167
+    }
168
+
169
+    public function getScope(): string {
170
+        $scope = parent::getScope();
171
+        if ($scope === null) {
172
+            return '';
173
+        }
174
+
175
+        return $scope;
176
+    }
177
+
178
+    public function getScopeAsArray(): array {
179
+        $scope = json_decode($this->getScope(), true);
180
+        if (!$scope) {
181
+            return [
182
+                'filesystem'=> true
183
+            ];
184
+        }
185
+        return $scope;
186
+    }
187
+
188
+    public function setScope($scope) {
189
+        if (is_array($scope)) {
190
+            parent::setScope(json_encode($scope));
191
+        } else {
192
+            parent::setScope((string)$scope);
193
+        }
194
+    }
195
+
196
+    public function getName(): string {
197
+        return parent::getName();
198
+    }
199
+
200
+    public function getRemember(): int {
201
+        return parent::getRemember();
202
+    }
203
+
204
+    public function setToken(string $token) {
205
+        parent::setToken($token);
206
+    }
207
+
208
+    public function setPassword(string $password = null) {
209
+        parent::setPassword($password);
210
+    }
211
+
212
+    public function setExpires($expires) {
213
+        parent::setExpires($expires);
214
+    }
215
+
216
+    /**
217
+     * @return int|null
218
+     */
219
+    public function getExpires() {
220
+        return parent::getExpires();
221
+    }
222
+
223
+    public function setPasswordInvalid(bool $invalid) {
224
+        parent::setPasswordInvalid($invalid);
225
+    }
226 226
 }
Please login to merge, or discard this patch.
lib/private/Authentication/Token/DefaultTokenProvider.php 1 patch
Indentation   +311 added lines, -311 removed lines patch added patch discarded remove patch
@@ -39,315 +39,315 @@
 block discarded – undo
39 39
 
40 40
 class DefaultTokenProvider implements IProvider {
41 41
 
42
-	/** @var DefaultTokenMapper */
43
-	private $mapper;
44
-
45
-	/** @var ICrypto */
46
-	private $crypto;
47
-
48
-	/** @var IConfig */
49
-	private $config;
50
-
51
-	/** @var ILogger $logger */
52
-	private $logger;
53
-
54
-	/** @var ITimeFactory $time */
55
-	private $time;
56
-
57
-	/**
58
-	 * @param DefaultTokenMapper $mapper
59
-	 * @param ICrypto $crypto
60
-	 * @param IConfig $config
61
-	 * @param ILogger $logger
62
-	 * @param ITimeFactory $time
63
-	 */
64
-	public function __construct(DefaultTokenMapper $mapper,
65
-								ICrypto $crypto,
66
-								IConfig $config,
67
-								ILogger $logger,
68
-								ITimeFactory $time) {
69
-		$this->mapper = $mapper;
70
-		$this->crypto = $crypto;
71
-		$this->config = $config;
72
-		$this->logger = $logger;
73
-		$this->time = $time;
74
-	}
75
-
76
-	/**
77
-	 * Create and persist a new token
78
-	 *
79
-	 * @param string $token
80
-	 * @param string $uid
81
-	 * @param string $loginName
82
-	 * @param string|null $password
83
-	 * @param string $name
84
-	 * @param int $type token type
85
-	 * @param int $remember whether the session token should be used for remember-me
86
-	 * @return IToken
87
-	 */
88
-	public function generateToken(string $token,
89
-								  string $uid,
90
-								  string $loginName,
91
-								  $password,
92
-								  string $name,
93
-								  int $type = IToken::TEMPORARY_TOKEN,
94
-								  int $remember = IToken::DO_NOT_REMEMBER): IToken {
95
-		$dbToken = new DefaultToken();
96
-		$dbToken->setUid($uid);
97
-		$dbToken->setLoginName($loginName);
98
-		if (!is_null($password)) {
99
-			$dbToken->setPassword($this->encryptPassword($password, $token));
100
-		}
101
-		$dbToken->setName($name);
102
-		$dbToken->setToken($this->hashToken($token));
103
-		$dbToken->setType($type);
104
-		$dbToken->setRemember($remember);
105
-		$dbToken->setLastActivity($this->time->getTime());
106
-		$dbToken->setLastCheck($this->time->getTime());
107
-		$dbToken->setVersion(DefaultToken::VERSION);
108
-
109
-		$this->mapper->insert($dbToken);
110
-
111
-		return $dbToken;
112
-	}
113
-
114
-	/**
115
-	 * Save the updated token
116
-	 *
117
-	 * @param IToken $token
118
-	 * @throws InvalidTokenException
119
-	 */
120
-	public function updateToken(IToken $token) {
121
-		if (!($token instanceof DefaultToken)) {
122
-			throw new InvalidTokenException();
123
-		}
124
-		$this->mapper->update($token);
125
-	}
126
-
127
-	/**
128
-	 * Update token activity timestamp
129
-	 *
130
-	 * @throws InvalidTokenException
131
-	 * @param IToken $token
132
-	 */
133
-	public function updateTokenActivity(IToken $token) {
134
-		if (!($token instanceof DefaultToken)) {
135
-			throw new InvalidTokenException();
136
-		}
137
-		/** @var DefaultToken $token */
138
-		$now = $this->time->getTime();
139
-		if ($token->getLastActivity() < ($now - 60)) {
140
-			// Update token only once per minute
141
-			$token->setLastActivity($now);
142
-			$this->mapper->update($token);
143
-		}
144
-	}
145
-
146
-	public function getTokenByUser(string $uid): array {
147
-		return $this->mapper->getTokenByUser($uid);
148
-	}
149
-
150
-	/**
151
-	 * Get a token by token
152
-	 *
153
-	 * @param string $tokenId
154
-	 * @throws InvalidTokenException
155
-	 * @throws ExpiredTokenException
156
-	 * @return IToken
157
-	 */
158
-	public function getToken(string $tokenId): IToken {
159
-		try {
160
-			$token = $this->mapper->getToken($this->hashToken($tokenId));
161
-		} catch (DoesNotExistException $ex) {
162
-			throw new InvalidTokenException();
163
-		}
164
-
165
-		if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
166
-			throw new ExpiredTokenException($token);
167
-		}
168
-
169
-		return $token;
170
-	}
171
-
172
-	/**
173
-	 * Get a token by token id
174
-	 *
175
-	 * @param int $tokenId
176
-	 * @throws InvalidTokenException
177
-	 * @throws ExpiredTokenException
178
-	 * @return IToken
179
-	 */
180
-	public function getTokenById(int $tokenId): IToken {
181
-		try {
182
-			$token = $this->mapper->getTokenById($tokenId);
183
-		} catch (DoesNotExistException $ex) {
184
-			throw new InvalidTokenException();
185
-		}
186
-
187
-		if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
188
-			throw new ExpiredTokenException($token);
189
-		}
190
-
191
-		return $token;
192
-	}
193
-
194
-	/**
195
-	 * @param string $oldSessionId
196
-	 * @param string $sessionId
197
-	 * @throws InvalidTokenException
198
-	 */
199
-	public function renewSessionToken(string $oldSessionId, string $sessionId) {
200
-		$token = $this->getToken($oldSessionId);
201
-
202
-		$newToken = new DefaultToken();
203
-		$newToken->setUid($token->getUID());
204
-		$newToken->setLoginName($token->getLoginName());
205
-		if (!is_null($token->getPassword())) {
206
-			$password = $this->decryptPassword($token->getPassword(), $oldSessionId);
207
-			$newToken->setPassword($this->encryptPassword($password, $sessionId));
208
-		}
209
-		$newToken->setName($token->getName());
210
-		$newToken->setToken($this->hashToken($sessionId));
211
-		$newToken->setType(IToken::TEMPORARY_TOKEN);
212
-		$newToken->setRemember($token->getRemember());
213
-		$newToken->setLastActivity($this->time->getTime());
214
-		$this->mapper->insert($newToken);
215
-		$this->mapper->delete($token);
216
-	}
217
-
218
-	/**
219
-	 * @param IToken $savedToken
220
-	 * @param string $tokenId session token
221
-	 * @throws InvalidTokenException
222
-	 * @throws PasswordlessTokenException
223
-	 * @return string
224
-	 */
225
-	public function getPassword(IToken $savedToken, string $tokenId): string {
226
-		$password = $savedToken->getPassword();
227
-		if (is_null($password)) {
228
-			throw new PasswordlessTokenException();
229
-		}
230
-		return $this->decryptPassword($password, $tokenId);
231
-	}
232
-
233
-	/**
234
-	 * Encrypt and set the password of the given token
235
-	 *
236
-	 * @param IToken $token
237
-	 * @param string $tokenId
238
-	 * @param string $password
239
-	 * @throws InvalidTokenException
240
-	 */
241
-	public function setPassword(IToken $token, string $tokenId, string $password) {
242
-		if (!($token instanceof DefaultToken)) {
243
-			throw new InvalidTokenException();
244
-		}
245
-		/** @var DefaultToken $token */
246
-		$token->setPassword($this->encryptPassword($password, $tokenId));
247
-		$this->mapper->update($token);
248
-	}
249
-
250
-	/**
251
-	 * Invalidate (delete) the given session token
252
-	 *
253
-	 * @param string $token
254
-	 */
255
-	public function invalidateToken(string $token) {
256
-		$this->mapper->invalidate($this->hashToken($token));
257
-	}
258
-
259
-	public function invalidateTokenById(string $uid, int $id) {
260
-		$this->mapper->deleteById($uid, $id);
261
-	}
262
-
263
-	/**
264
-	 * Invalidate (delete) old session tokens
265
-	 */
266
-	public function invalidateOldTokens() {
267
-		$olderThan = $this->time->getTime() - (int) $this->config->getSystemValue('session_lifetime', 60 * 60 * 24);
268
-		$this->logger->debug('Invalidating session tokens older than ' . date('c', $olderThan), ['app' => 'cron']);
269
-		$this->mapper->invalidateOld($olderThan, IToken::DO_NOT_REMEMBER);
270
-		$rememberThreshold = $this->time->getTime() - (int) $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
271
-		$this->logger->debug('Invalidating remembered session tokens older than ' . date('c', $rememberThreshold), ['app' => 'cron']);
272
-		$this->mapper->invalidateOld($rememberThreshold, IToken::REMEMBER);
273
-	}
274
-
275
-	/**
276
-	 * Rotate the token. Usefull for for example oauth tokens
277
-	 *
278
-	 * @param IToken $token
279
-	 * @param string $oldTokenId
280
-	 * @param string $newTokenId
281
-	 * @return IToken
282
-	 */
283
-	public function rotate(IToken $token, string $oldTokenId, string $newTokenId): IToken {
284
-		try {
285
-			$password = $this->getPassword($token, $oldTokenId);
286
-			$token->setPassword($this->encryptPassword($password, $newTokenId));
287
-		} catch (PasswordlessTokenException $e) {
288
-
289
-		}
290
-
291
-		$token->setToken($this->hashToken($newTokenId));
292
-		$this->updateToken($token);
293
-
294
-		return $token;
295
-	}
296
-
297
-	/**
298
-	 * @param string $token
299
-	 * @return string
300
-	 */
301
-	private function hashToken(string $token): string {
302
-		$secret = $this->config->getSystemValue('secret');
303
-		return hash('sha512', $token . $secret);
304
-	}
305
-
306
-	/**
307
-	 * Encrypt the given password
308
-	 *
309
-	 * The token is used as key
310
-	 *
311
-	 * @param string $password
312
-	 * @param string $token
313
-	 * @return string encrypted password
314
-	 */
315
-	private function encryptPassword(string $password, string $token): string {
316
-		$secret = $this->config->getSystemValue('secret');
317
-		return $this->crypto->encrypt($password, $token . $secret);
318
-	}
319
-
320
-	/**
321
-	 * Decrypt the given password
322
-	 *
323
-	 * The token is used as key
324
-	 *
325
-	 * @param string $password
326
-	 * @param string $token
327
-	 * @throws InvalidTokenException
328
-	 * @return string the decrypted key
329
-	 */
330
-	private function decryptPassword(string $password, string $token): string {
331
-		$secret = $this->config->getSystemValue('secret');
332
-		try {
333
-			return $this->crypto->decrypt($password, $token . $secret);
334
-		} catch (Exception $ex) {
335
-			// Delete the invalid token
336
-			$this->invalidateToken($token);
337
-			throw new InvalidTokenException();
338
-		}
339
-	}
340
-
341
-	public function markPasswordInvalid(IToken $token, string $tokenId) {
342
-		if (!($token instanceof DefaultToken)) {
343
-			throw new InvalidTokenException();
344
-		}
345
-
346
-		//No need to mark as invalid. We just invalide default tokens
347
-		$this->invalidateToken($tokenId);
348
-	}
349
-
350
-	public function updatePasswords(string $uid, string $password) {
351
-		// Nothing to do here
352
-	}
42
+    /** @var DefaultTokenMapper */
43
+    private $mapper;
44
+
45
+    /** @var ICrypto */
46
+    private $crypto;
47
+
48
+    /** @var IConfig */
49
+    private $config;
50
+
51
+    /** @var ILogger $logger */
52
+    private $logger;
53
+
54
+    /** @var ITimeFactory $time */
55
+    private $time;
56
+
57
+    /**
58
+     * @param DefaultTokenMapper $mapper
59
+     * @param ICrypto $crypto
60
+     * @param IConfig $config
61
+     * @param ILogger $logger
62
+     * @param ITimeFactory $time
63
+     */
64
+    public function __construct(DefaultTokenMapper $mapper,
65
+                                ICrypto $crypto,
66
+                                IConfig $config,
67
+                                ILogger $logger,
68
+                                ITimeFactory $time) {
69
+        $this->mapper = $mapper;
70
+        $this->crypto = $crypto;
71
+        $this->config = $config;
72
+        $this->logger = $logger;
73
+        $this->time = $time;
74
+    }
75
+
76
+    /**
77
+     * Create and persist a new token
78
+     *
79
+     * @param string $token
80
+     * @param string $uid
81
+     * @param string $loginName
82
+     * @param string|null $password
83
+     * @param string $name
84
+     * @param int $type token type
85
+     * @param int $remember whether the session token should be used for remember-me
86
+     * @return IToken
87
+     */
88
+    public function generateToken(string $token,
89
+                                    string $uid,
90
+                                    string $loginName,
91
+                                    $password,
92
+                                    string $name,
93
+                                    int $type = IToken::TEMPORARY_TOKEN,
94
+                                    int $remember = IToken::DO_NOT_REMEMBER): IToken {
95
+        $dbToken = new DefaultToken();
96
+        $dbToken->setUid($uid);
97
+        $dbToken->setLoginName($loginName);
98
+        if (!is_null($password)) {
99
+            $dbToken->setPassword($this->encryptPassword($password, $token));
100
+        }
101
+        $dbToken->setName($name);
102
+        $dbToken->setToken($this->hashToken($token));
103
+        $dbToken->setType($type);
104
+        $dbToken->setRemember($remember);
105
+        $dbToken->setLastActivity($this->time->getTime());
106
+        $dbToken->setLastCheck($this->time->getTime());
107
+        $dbToken->setVersion(DefaultToken::VERSION);
108
+
109
+        $this->mapper->insert($dbToken);
110
+
111
+        return $dbToken;
112
+    }
113
+
114
+    /**
115
+     * Save the updated token
116
+     *
117
+     * @param IToken $token
118
+     * @throws InvalidTokenException
119
+     */
120
+    public function updateToken(IToken $token) {
121
+        if (!($token instanceof DefaultToken)) {
122
+            throw new InvalidTokenException();
123
+        }
124
+        $this->mapper->update($token);
125
+    }
126
+
127
+    /**
128
+     * Update token activity timestamp
129
+     *
130
+     * @throws InvalidTokenException
131
+     * @param IToken $token
132
+     */
133
+    public function updateTokenActivity(IToken $token) {
134
+        if (!($token instanceof DefaultToken)) {
135
+            throw new InvalidTokenException();
136
+        }
137
+        /** @var DefaultToken $token */
138
+        $now = $this->time->getTime();
139
+        if ($token->getLastActivity() < ($now - 60)) {
140
+            // Update token only once per minute
141
+            $token->setLastActivity($now);
142
+            $this->mapper->update($token);
143
+        }
144
+    }
145
+
146
+    public function getTokenByUser(string $uid): array {
147
+        return $this->mapper->getTokenByUser($uid);
148
+    }
149
+
150
+    /**
151
+     * Get a token by token
152
+     *
153
+     * @param string $tokenId
154
+     * @throws InvalidTokenException
155
+     * @throws ExpiredTokenException
156
+     * @return IToken
157
+     */
158
+    public function getToken(string $tokenId): IToken {
159
+        try {
160
+            $token = $this->mapper->getToken($this->hashToken($tokenId));
161
+        } catch (DoesNotExistException $ex) {
162
+            throw new InvalidTokenException();
163
+        }
164
+
165
+        if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
166
+            throw new ExpiredTokenException($token);
167
+        }
168
+
169
+        return $token;
170
+    }
171
+
172
+    /**
173
+     * Get a token by token id
174
+     *
175
+     * @param int $tokenId
176
+     * @throws InvalidTokenException
177
+     * @throws ExpiredTokenException
178
+     * @return IToken
179
+     */
180
+    public function getTokenById(int $tokenId): IToken {
181
+        try {
182
+            $token = $this->mapper->getTokenById($tokenId);
183
+        } catch (DoesNotExistException $ex) {
184
+            throw new InvalidTokenException();
185
+        }
186
+
187
+        if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
188
+            throw new ExpiredTokenException($token);
189
+        }
190
+
191
+        return $token;
192
+    }
193
+
194
+    /**
195
+     * @param string $oldSessionId
196
+     * @param string $sessionId
197
+     * @throws InvalidTokenException
198
+     */
199
+    public function renewSessionToken(string $oldSessionId, string $sessionId) {
200
+        $token = $this->getToken($oldSessionId);
201
+
202
+        $newToken = new DefaultToken();
203
+        $newToken->setUid($token->getUID());
204
+        $newToken->setLoginName($token->getLoginName());
205
+        if (!is_null($token->getPassword())) {
206
+            $password = $this->decryptPassword($token->getPassword(), $oldSessionId);
207
+            $newToken->setPassword($this->encryptPassword($password, $sessionId));
208
+        }
209
+        $newToken->setName($token->getName());
210
+        $newToken->setToken($this->hashToken($sessionId));
211
+        $newToken->setType(IToken::TEMPORARY_TOKEN);
212
+        $newToken->setRemember($token->getRemember());
213
+        $newToken->setLastActivity($this->time->getTime());
214
+        $this->mapper->insert($newToken);
215
+        $this->mapper->delete($token);
216
+    }
217
+
218
+    /**
219
+     * @param IToken $savedToken
220
+     * @param string $tokenId session token
221
+     * @throws InvalidTokenException
222
+     * @throws PasswordlessTokenException
223
+     * @return string
224
+     */
225
+    public function getPassword(IToken $savedToken, string $tokenId): string {
226
+        $password = $savedToken->getPassword();
227
+        if (is_null($password)) {
228
+            throw new PasswordlessTokenException();
229
+        }
230
+        return $this->decryptPassword($password, $tokenId);
231
+    }
232
+
233
+    /**
234
+     * Encrypt and set the password of the given token
235
+     *
236
+     * @param IToken $token
237
+     * @param string $tokenId
238
+     * @param string $password
239
+     * @throws InvalidTokenException
240
+     */
241
+    public function setPassword(IToken $token, string $tokenId, string $password) {
242
+        if (!($token instanceof DefaultToken)) {
243
+            throw new InvalidTokenException();
244
+        }
245
+        /** @var DefaultToken $token */
246
+        $token->setPassword($this->encryptPassword($password, $tokenId));
247
+        $this->mapper->update($token);
248
+    }
249
+
250
+    /**
251
+     * Invalidate (delete) the given session token
252
+     *
253
+     * @param string $token
254
+     */
255
+    public function invalidateToken(string $token) {
256
+        $this->mapper->invalidate($this->hashToken($token));
257
+    }
258
+
259
+    public function invalidateTokenById(string $uid, int $id) {
260
+        $this->mapper->deleteById($uid, $id);
261
+    }
262
+
263
+    /**
264
+     * Invalidate (delete) old session tokens
265
+     */
266
+    public function invalidateOldTokens() {
267
+        $olderThan = $this->time->getTime() - (int) $this->config->getSystemValue('session_lifetime', 60 * 60 * 24);
268
+        $this->logger->debug('Invalidating session tokens older than ' . date('c', $olderThan), ['app' => 'cron']);
269
+        $this->mapper->invalidateOld($olderThan, IToken::DO_NOT_REMEMBER);
270
+        $rememberThreshold = $this->time->getTime() - (int) $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
271
+        $this->logger->debug('Invalidating remembered session tokens older than ' . date('c', $rememberThreshold), ['app' => 'cron']);
272
+        $this->mapper->invalidateOld($rememberThreshold, IToken::REMEMBER);
273
+    }
274
+
275
+    /**
276
+     * Rotate the token. Usefull for for example oauth tokens
277
+     *
278
+     * @param IToken $token
279
+     * @param string $oldTokenId
280
+     * @param string $newTokenId
281
+     * @return IToken
282
+     */
283
+    public function rotate(IToken $token, string $oldTokenId, string $newTokenId): IToken {
284
+        try {
285
+            $password = $this->getPassword($token, $oldTokenId);
286
+            $token->setPassword($this->encryptPassword($password, $newTokenId));
287
+        } catch (PasswordlessTokenException $e) {
288
+
289
+        }
290
+
291
+        $token->setToken($this->hashToken($newTokenId));
292
+        $this->updateToken($token);
293
+
294
+        return $token;
295
+    }
296
+
297
+    /**
298
+     * @param string $token
299
+     * @return string
300
+     */
301
+    private function hashToken(string $token): string {
302
+        $secret = $this->config->getSystemValue('secret');
303
+        return hash('sha512', $token . $secret);
304
+    }
305
+
306
+    /**
307
+     * Encrypt the given password
308
+     *
309
+     * The token is used as key
310
+     *
311
+     * @param string $password
312
+     * @param string $token
313
+     * @return string encrypted password
314
+     */
315
+    private function encryptPassword(string $password, string $token): string {
316
+        $secret = $this->config->getSystemValue('secret');
317
+        return $this->crypto->encrypt($password, $token . $secret);
318
+    }
319
+
320
+    /**
321
+     * Decrypt the given password
322
+     *
323
+     * The token is used as key
324
+     *
325
+     * @param string $password
326
+     * @param string $token
327
+     * @throws InvalidTokenException
328
+     * @return string the decrypted key
329
+     */
330
+    private function decryptPassword(string $password, string $token): string {
331
+        $secret = $this->config->getSystemValue('secret');
332
+        try {
333
+            return $this->crypto->decrypt($password, $token . $secret);
334
+        } catch (Exception $ex) {
335
+            // Delete the invalid token
336
+            $this->invalidateToken($token);
337
+            throw new InvalidTokenException();
338
+        }
339
+    }
340
+
341
+    public function markPasswordInvalid(IToken $token, string $tokenId) {
342
+        if (!($token instanceof DefaultToken)) {
343
+            throw new InvalidTokenException();
344
+        }
345
+
346
+        //No need to mark as invalid. We just invalide default tokens
347
+        $this->invalidateToken($tokenId);
348
+    }
349
+
350
+    public function updatePasswords(string $uid, string $password) {
351
+        // Nothing to do here
352
+    }
353 353
 }
Please login to merge, or discard this patch.
lib/private/Authentication/Token/IProvider.php 1 patch
Indentation   +140 added lines, -140 removed lines patch added patch discarded remove patch
@@ -32,144 +32,144 @@
 block discarded – undo
32 32
 interface IProvider {
33 33
 
34 34
 
35
-	/**
36
-	 * Create and persist a new token
37
-	 *
38
-	 * @param string $token
39
-	 * @param string $uid
40
-	 * @param string $loginName
41
-	 * @param string|null $password
42
-	 * @param string $name
43
-	 * @param int $type token type
44
-	 * @param int $remember whether the session token should be used for remember-me
45
-	 * @return IToken
46
-	 */
47
-	public function generateToken(string $token,
48
-								  string $uid,
49
-								  string $loginName,
50
-								  $password,
51
-								  string $name,
52
-								  int $type = IToken::TEMPORARY_TOKEN,
53
-								  int $remember = IToken::DO_NOT_REMEMBER): IToken;
54
-
55
-	/**
56
-	 * Get a token by token id
57
-	 *
58
-	 * @param string $tokenId
59
-	 * @throws InvalidTokenException
60
-	 * @throws ExpiredTokenException
61
-	 * @return IToken
62
-	 */
63
-	public function getToken(string $tokenId): IToken;
64
-
65
-	/**
66
-	 * Get a token by token id
67
-	 *
68
-	 * @param int $tokenId
69
-	 * @throws InvalidTokenException
70
-	 * @throws ExpiredTokenException
71
-	 * @return IToken
72
-	 */
73
-	public function getTokenById(int $tokenId): IToken;
74
-
75
-	/**
76
-	 * Duplicate an existing session token
77
-	 *
78
-	 * @param string $oldSessionId
79
-	 * @param string $sessionId
80
-	 * @throws InvalidTokenException
81
-	 */
82
-	public function renewSessionToken(string $oldSessionId, string $sessionId);
83
-
84
-	/**
85
-	 * Invalidate (delete) the given session token
86
-	 *
87
-	 * @param string $token
88
-	 */
89
-	public function invalidateToken(string $token);
90
-
91
-	/**
92
-	 * Invalidate (delete) the given token
93
-	 *
94
-	 * @param string $uid
95
-	 * @param int $id
96
-	 */
97
-	public function invalidateTokenById(string $uid, int $id);
98
-
99
-	/**
100
-	 * Invalidate (delete) old session tokens
101
-	 */
102
-	public function invalidateOldTokens();
103
-
104
-	/**
105
-	 * Save the updated token
106
-	 *
107
-	 * @param IToken $token
108
-	 */
109
-	public function updateToken(IToken $token);
110
-
111
-	/**
112
-	 * Update token activity timestamp
113
-	 *
114
-	 * @param IToken $token
115
-	 */
116
-	public function updateTokenActivity(IToken $token);
117
-
118
-	/**
119
-	 * Get all tokens of a user
120
-	 *
121
-	 * The provider may limit the number of result rows in case of an abuse
122
-	 * where a high number of (session) tokens is generated
123
-	 *
124
-	 * @param string $uid
125
-	 * @return IToken[]
126
-	 */
127
-	public function getTokenByUser(string $uid): array;
128
-
129
-	/**
130
-	 * Get the (unencrypted) password of the given token
131
-	 *
132
-	 * @param IToken $token
133
-	 * @param string $tokenId
134
-	 * @throws InvalidTokenException
135
-	 * @throws PasswordlessTokenException
136
-	 * @return string
137
-	 */
138
-	public function getPassword(IToken $token, string $tokenId): string;
139
-
140
-	/**
141
-	 * Encrypt and set the password of the given token
142
-	 *
143
-	 * @param IToken $token
144
-	 * @param string $tokenId
145
-	 * @param string $password
146
-	 * @throws InvalidTokenException
147
-	 */
148
-	public function setPassword(IToken $token, string $tokenId, string $password);
149
-
150
-	/**
151
-	 * Rotate the token. Usefull for for example oauth tokens
152
-	 *
153
-	 * @param IToken $token
154
-	 * @param string $oldTokenId
155
-	 * @param string $newTokenId
156
-	 * @return IToken
157
-	 */
158
-	public function rotate(IToken $token, string $oldTokenId, string $newTokenId): IToken;
159
-
160
-	/**
161
-	 * Marks a token as having an invalid password.
162
-	 *
163
-	 * @param IToken $token
164
-	 * @param string $tokenId
165
-	 */
166
-	public function markPasswordInvalid(IToken $token, string $tokenId);
167
-
168
-	/**
169
-	 * Update all the passwords of $uid if required
170
-	 *
171
-	 * @param string $uid
172
-	 * @param string $password
173
-	 */
174
-	public function updatePasswords(string $uid, string $password);
35
+    /**
36
+     * Create and persist a new token
37
+     *
38
+     * @param string $token
39
+     * @param string $uid
40
+     * @param string $loginName
41
+     * @param string|null $password
42
+     * @param string $name
43
+     * @param int $type token type
44
+     * @param int $remember whether the session token should be used for remember-me
45
+     * @return IToken
46
+     */
47
+    public function generateToken(string $token,
48
+                                    string $uid,
49
+                                    string $loginName,
50
+                                    $password,
51
+                                    string $name,
52
+                                    int $type = IToken::TEMPORARY_TOKEN,
53
+                                    int $remember = IToken::DO_NOT_REMEMBER): IToken;
54
+
55
+    /**
56
+     * Get a token by token id
57
+     *
58
+     * @param string $tokenId
59
+     * @throws InvalidTokenException
60
+     * @throws ExpiredTokenException
61
+     * @return IToken
62
+     */
63
+    public function getToken(string $tokenId): IToken;
64
+
65
+    /**
66
+     * Get a token by token id
67
+     *
68
+     * @param int $tokenId
69
+     * @throws InvalidTokenException
70
+     * @throws ExpiredTokenException
71
+     * @return IToken
72
+     */
73
+    public function getTokenById(int $tokenId): IToken;
74
+
75
+    /**
76
+     * Duplicate an existing session token
77
+     *
78
+     * @param string $oldSessionId
79
+     * @param string $sessionId
80
+     * @throws InvalidTokenException
81
+     */
82
+    public function renewSessionToken(string $oldSessionId, string $sessionId);
83
+
84
+    /**
85
+     * Invalidate (delete) the given session token
86
+     *
87
+     * @param string $token
88
+     */
89
+    public function invalidateToken(string $token);
90
+
91
+    /**
92
+     * Invalidate (delete) the given token
93
+     *
94
+     * @param string $uid
95
+     * @param int $id
96
+     */
97
+    public function invalidateTokenById(string $uid, int $id);
98
+
99
+    /**
100
+     * Invalidate (delete) old session tokens
101
+     */
102
+    public function invalidateOldTokens();
103
+
104
+    /**
105
+     * Save the updated token
106
+     *
107
+     * @param IToken $token
108
+     */
109
+    public function updateToken(IToken $token);
110
+
111
+    /**
112
+     * Update token activity timestamp
113
+     *
114
+     * @param IToken $token
115
+     */
116
+    public function updateTokenActivity(IToken $token);
117
+
118
+    /**
119
+     * Get all tokens of a user
120
+     *
121
+     * The provider may limit the number of result rows in case of an abuse
122
+     * where a high number of (session) tokens is generated
123
+     *
124
+     * @param string $uid
125
+     * @return IToken[]
126
+     */
127
+    public function getTokenByUser(string $uid): array;
128
+
129
+    /**
130
+     * Get the (unencrypted) password of the given token
131
+     *
132
+     * @param IToken $token
133
+     * @param string $tokenId
134
+     * @throws InvalidTokenException
135
+     * @throws PasswordlessTokenException
136
+     * @return string
137
+     */
138
+    public function getPassword(IToken $token, string $tokenId): string;
139
+
140
+    /**
141
+     * Encrypt and set the password of the given token
142
+     *
143
+     * @param IToken $token
144
+     * @param string $tokenId
145
+     * @param string $password
146
+     * @throws InvalidTokenException
147
+     */
148
+    public function setPassword(IToken $token, string $tokenId, string $password);
149
+
150
+    /**
151
+     * Rotate the token. Usefull for for example oauth tokens
152
+     *
153
+     * @param IToken $token
154
+     * @param string $oldTokenId
155
+     * @param string $newTokenId
156
+     * @return IToken
157
+     */
158
+    public function rotate(IToken $token, string $oldTokenId, string $newTokenId): IToken;
159
+
160
+    /**
161
+     * Marks a token as having an invalid password.
162
+     *
163
+     * @param IToken $token
164
+     * @param string $tokenId
165
+     */
166
+    public function markPasswordInvalid(IToken $token, string $tokenId);
167
+
168
+    /**
169
+     * Update all the passwords of $uid if required
170
+     *
171
+     * @param string $uid
172
+     * @param string $password
173
+     */
174
+    public function updatePasswords(string $uid, string $password);
175 175
 }
Please login to merge, or discard this patch.
lib/private/Authentication/Token/PublicKeyTokenMapper.php 1 patch
Indentation   +153 added lines, -153 removed lines patch added patch discarded remove patch
@@ -31,157 +31,157 @@
 block discarded – undo
31 31
 
32 32
 class PublicKeyTokenMapper extends QBMapper {
33 33
 
34
-	public function __construct(IDBConnection $db) {
35
-		parent::__construct($db, 'authtoken');
36
-	}
37
-
38
-	/**
39
-	 * Invalidate (delete) a given token
40
-	 *
41
-	 * @param string $token
42
-	 */
43
-	public function invalidate(string $token) {
44
-		/* @var $qb IQueryBuilder */
45
-		$qb = $this->db->getQueryBuilder();
46
-		$qb->delete('authtoken')
47
-			->where($qb->expr()->eq('token', $qb->createNamedParameter($token)))
48
-			->andWhere($qb->expr()->eq('version', $qb->createNamedParameter(PublicKeyToken::VERSION, IQueryBuilder::PARAM_INT)))
49
-			->execute();
50
-	}
51
-
52
-	/**
53
-	 * @param int $olderThan
54
-	 * @param int $remember
55
-	 */
56
-	public function invalidateOld(int $olderThan, int $remember = IToken::DO_NOT_REMEMBER) {
57
-		/* @var $qb IQueryBuilder */
58
-		$qb = $this->db->getQueryBuilder();
59
-		$qb->delete('authtoken')
60
-			->where($qb->expr()->lt('last_activity', $qb->createNamedParameter($olderThan, IQueryBuilder::PARAM_INT)))
61
-			->andWhere($qb->expr()->eq('type', $qb->createNamedParameter(IToken::TEMPORARY_TOKEN, IQueryBuilder::PARAM_INT)))
62
-			->andWhere($qb->expr()->eq('remember', $qb->createNamedParameter($remember, IQueryBuilder::PARAM_INT)))
63
-			->andWhere($qb->expr()->eq('version', $qb->createNamedParameter(PublicKeyToken::VERSION, IQueryBuilder::PARAM_INT)))
64
-			->execute();
65
-	}
66
-
67
-	/**
68
-	 * Get the user UID for the given token
69
-	 *
70
-	 * @throws DoesNotExistException
71
-	 */
72
-	public function getToken(string $token): PublicKeyToken {
73
-		/* @var $qb IQueryBuilder */
74
-		$qb = $this->db->getQueryBuilder();
75
-		$result = $qb->select('*')
76
-			->from('authtoken')
77
-			->where($qb->expr()->eq('token', $qb->createNamedParameter($token)))
78
-			->andWhere($qb->expr()->eq('version', $qb->createNamedParameter(PublicKeyToken::VERSION, IQueryBuilder::PARAM_INT)))
79
-			->execute();
80
-
81
-		$data = $result->fetch();
82
-		$result->closeCursor();
83
-		if ($data === false) {
84
-			throw new DoesNotExistException('token does not exist');
85
-		}
86
-		return PublicKeyToken::fromRow($data);
87
-	}
88
-
89
-	/**
90
-	 * Get the token for $id
91
-	 *
92
-	 * @throws DoesNotExistException
93
-	 */
94
-	public function getTokenById(int $id): PublicKeyToken {
95
-		/* @var $qb IQueryBuilder */
96
-		$qb = $this->db->getQueryBuilder();
97
-		$result = $qb->select('*')
98
-			->from('authtoken')
99
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
100
-			->andWhere($qb->expr()->eq('version', $qb->createNamedParameter(PublicKeyToken::VERSION, IQueryBuilder::PARAM_INT)))
101
-			->execute();
102
-
103
-		$data = $result->fetch();
104
-		$result->closeCursor();
105
-		if ($data === false) {
106
-			throw new DoesNotExistException('token does not exist');
107
-		}
108
-		return PublicKeyToken::fromRow($data);
109
-	}
110
-
111
-	/**
112
-	 * Get all tokens of a user
113
-	 *
114
-	 * The provider may limit the number of result rows in case of an abuse
115
-	 * where a high number of (session) tokens is generated
116
-	 *
117
-	 * @param string $uid
118
-	 * @return PublicKeyToken[]
119
-	 */
120
-	public function getTokenByUser(string $uid): array {
121
-		/* @var $qb IQueryBuilder */
122
-		$qb = $this->db->getQueryBuilder();
123
-		$qb->select('*')
124
-			->from('authtoken')
125
-			->where($qb->expr()->eq('uid', $qb->createNamedParameter($uid)))
126
-			->andWhere($qb->expr()->eq('version', $qb->createNamedParameter(PublicKeyToken::VERSION, IQueryBuilder::PARAM_INT)))
127
-			->setMaxResults(1000);
128
-		$result = $qb->execute();
129
-		$data = $result->fetchAll();
130
-		$result->closeCursor();
131
-
132
-		$entities = array_map(function ($row) {
133
-			return PublicKeyToken::fromRow($row);
134
-		}, $data);
135
-
136
-		return $entities;
137
-	}
138
-
139
-	public function deleteById(string $uid, int $id) {
140
-		/* @var $qb IQueryBuilder */
141
-		$qb = $this->db->getQueryBuilder();
142
-		$qb->delete('authtoken')
143
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
144
-			->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter($uid)))
145
-			->andWhere($qb->expr()->eq('version', $qb->createNamedParameter(PublicKeyToken::VERSION, IQueryBuilder::PARAM_INT)));
146
-		$qb->execute();
147
-	}
148
-
149
-	/**
150
-	 * delete all auth token which belong to a specific client if the client was deleted
151
-	 *
152
-	 * @param string $name
153
-	 */
154
-	public function deleteByName(string $name) {
155
-		$qb = $this->db->getQueryBuilder();
156
-		$qb->delete('authtoken')
157
-			->where($qb->expr()->eq('name', $qb->createNamedParameter($name), IQueryBuilder::PARAM_STR))
158
-			->andWhere($qb->expr()->eq('version', $qb->createNamedParameter(PublicKeyToken::VERSION, IQueryBuilder::PARAM_INT)));
159
-		$qb->execute();
160
-	}
161
-
162
-	public function deleteTempToken(PublicKeyToken $except) {
163
-		$qb = $this->db->getQueryBuilder();
164
-
165
-		$qb->delete('authtoken')
166
-			->where($qb->expr()->eq('type', $qb->createNamedParameter(IToken::TEMPORARY_TOKEN)))
167
-			->andWhere($qb->expr()->neq('id', $qb->createNamedParameter($except->getId())))
168
-			->andWhere($qb->expr()->eq('version', $qb->createNamedParameter(PublicKeyToken::VERSION, IQueryBuilder::PARAM_INT)));
169
-
170
-		$qb->execute();
171
-	}
172
-
173
-	public function hasExpiredTokens(string $uid): bool {
174
-		$qb = $this->db->getQueryBuilder();
175
-		$qb->select('*')
176
-			->from('authtoken')
177
-			->where($qb->expr()->eq('uid', $qb->createNamedParameter($uid)))
178
-			->andWhere($qb->expr()->eq('password_invalid', $qb->createNamedParameter(true), IQueryBuilder::PARAM_BOOL))
179
-			->setMaxResults(1);
180
-
181
-		$cursor = $qb->execute();
182
-		$data = $cursor->fetchAll();
183
-		$cursor->closeCursor();
184
-
185
-		return count($data) === 1;
186
-	}
34
+    public function __construct(IDBConnection $db) {
35
+        parent::__construct($db, 'authtoken');
36
+    }
37
+
38
+    /**
39
+     * Invalidate (delete) a given token
40
+     *
41
+     * @param string $token
42
+     */
43
+    public function invalidate(string $token) {
44
+        /* @var $qb IQueryBuilder */
45
+        $qb = $this->db->getQueryBuilder();
46
+        $qb->delete('authtoken')
47
+            ->where($qb->expr()->eq('token', $qb->createNamedParameter($token)))
48
+            ->andWhere($qb->expr()->eq('version', $qb->createNamedParameter(PublicKeyToken::VERSION, IQueryBuilder::PARAM_INT)))
49
+            ->execute();
50
+    }
51
+
52
+    /**
53
+     * @param int $olderThan
54
+     * @param int $remember
55
+     */
56
+    public function invalidateOld(int $olderThan, int $remember = IToken::DO_NOT_REMEMBER) {
57
+        /* @var $qb IQueryBuilder */
58
+        $qb = $this->db->getQueryBuilder();
59
+        $qb->delete('authtoken')
60
+            ->where($qb->expr()->lt('last_activity', $qb->createNamedParameter($olderThan, IQueryBuilder::PARAM_INT)))
61
+            ->andWhere($qb->expr()->eq('type', $qb->createNamedParameter(IToken::TEMPORARY_TOKEN, IQueryBuilder::PARAM_INT)))
62
+            ->andWhere($qb->expr()->eq('remember', $qb->createNamedParameter($remember, IQueryBuilder::PARAM_INT)))
63
+            ->andWhere($qb->expr()->eq('version', $qb->createNamedParameter(PublicKeyToken::VERSION, IQueryBuilder::PARAM_INT)))
64
+            ->execute();
65
+    }
66
+
67
+    /**
68
+     * Get the user UID for the given token
69
+     *
70
+     * @throws DoesNotExistException
71
+     */
72
+    public function getToken(string $token): PublicKeyToken {
73
+        /* @var $qb IQueryBuilder */
74
+        $qb = $this->db->getQueryBuilder();
75
+        $result = $qb->select('*')
76
+            ->from('authtoken')
77
+            ->where($qb->expr()->eq('token', $qb->createNamedParameter($token)))
78
+            ->andWhere($qb->expr()->eq('version', $qb->createNamedParameter(PublicKeyToken::VERSION, IQueryBuilder::PARAM_INT)))
79
+            ->execute();
80
+
81
+        $data = $result->fetch();
82
+        $result->closeCursor();
83
+        if ($data === false) {
84
+            throw new DoesNotExistException('token does not exist');
85
+        }
86
+        return PublicKeyToken::fromRow($data);
87
+    }
88
+
89
+    /**
90
+     * Get the token for $id
91
+     *
92
+     * @throws DoesNotExistException
93
+     */
94
+    public function getTokenById(int $id): PublicKeyToken {
95
+        /* @var $qb IQueryBuilder */
96
+        $qb = $this->db->getQueryBuilder();
97
+        $result = $qb->select('*')
98
+            ->from('authtoken')
99
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
100
+            ->andWhere($qb->expr()->eq('version', $qb->createNamedParameter(PublicKeyToken::VERSION, IQueryBuilder::PARAM_INT)))
101
+            ->execute();
102
+
103
+        $data = $result->fetch();
104
+        $result->closeCursor();
105
+        if ($data === false) {
106
+            throw new DoesNotExistException('token does not exist');
107
+        }
108
+        return PublicKeyToken::fromRow($data);
109
+    }
110
+
111
+    /**
112
+     * Get all tokens of a user
113
+     *
114
+     * The provider may limit the number of result rows in case of an abuse
115
+     * where a high number of (session) tokens is generated
116
+     *
117
+     * @param string $uid
118
+     * @return PublicKeyToken[]
119
+     */
120
+    public function getTokenByUser(string $uid): array {
121
+        /* @var $qb IQueryBuilder */
122
+        $qb = $this->db->getQueryBuilder();
123
+        $qb->select('*')
124
+            ->from('authtoken')
125
+            ->where($qb->expr()->eq('uid', $qb->createNamedParameter($uid)))
126
+            ->andWhere($qb->expr()->eq('version', $qb->createNamedParameter(PublicKeyToken::VERSION, IQueryBuilder::PARAM_INT)))
127
+            ->setMaxResults(1000);
128
+        $result = $qb->execute();
129
+        $data = $result->fetchAll();
130
+        $result->closeCursor();
131
+
132
+        $entities = array_map(function ($row) {
133
+            return PublicKeyToken::fromRow($row);
134
+        }, $data);
135
+
136
+        return $entities;
137
+    }
138
+
139
+    public function deleteById(string $uid, int $id) {
140
+        /* @var $qb IQueryBuilder */
141
+        $qb = $this->db->getQueryBuilder();
142
+        $qb->delete('authtoken')
143
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
144
+            ->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter($uid)))
145
+            ->andWhere($qb->expr()->eq('version', $qb->createNamedParameter(PublicKeyToken::VERSION, IQueryBuilder::PARAM_INT)));
146
+        $qb->execute();
147
+    }
148
+
149
+    /**
150
+     * delete all auth token which belong to a specific client if the client was deleted
151
+     *
152
+     * @param string $name
153
+     */
154
+    public function deleteByName(string $name) {
155
+        $qb = $this->db->getQueryBuilder();
156
+        $qb->delete('authtoken')
157
+            ->where($qb->expr()->eq('name', $qb->createNamedParameter($name), IQueryBuilder::PARAM_STR))
158
+            ->andWhere($qb->expr()->eq('version', $qb->createNamedParameter(PublicKeyToken::VERSION, IQueryBuilder::PARAM_INT)));
159
+        $qb->execute();
160
+    }
161
+
162
+    public function deleteTempToken(PublicKeyToken $except) {
163
+        $qb = $this->db->getQueryBuilder();
164
+
165
+        $qb->delete('authtoken')
166
+            ->where($qb->expr()->eq('type', $qb->createNamedParameter(IToken::TEMPORARY_TOKEN)))
167
+            ->andWhere($qb->expr()->neq('id', $qb->createNamedParameter($except->getId())))
168
+            ->andWhere($qb->expr()->eq('version', $qb->createNamedParameter(PublicKeyToken::VERSION, IQueryBuilder::PARAM_INT)));
169
+
170
+        $qb->execute();
171
+    }
172
+
173
+    public function hasExpiredTokens(string $uid): bool {
174
+        $qb = $this->db->getQueryBuilder();
175
+        $qb->select('*')
176
+            ->from('authtoken')
177
+            ->where($qb->expr()->eq('uid', $qb->createNamedParameter($uid)))
178
+            ->andWhere($qb->expr()->eq('password_invalid', $qb->createNamedParameter(true), IQueryBuilder::PARAM_BOOL))
179
+            ->setMaxResults(1);
180
+
181
+        $cursor = $qb->execute();
182
+        $data = $cursor->fetchAll();
183
+        $cursor->closeCursor();
184
+
185
+        return count($data) === 1;
186
+    }
187 187
 }
Please login to merge, or discard this patch.
lib/private/Authentication/Token/PublicKeyTokenProvider.php 1 patch
Indentation   +309 added lines, -309 removed lines patch added patch discarded remove patch
@@ -32,315 +32,315 @@
 block discarded – undo
32 32
 use OCP\Security\ICrypto;
33 33
 
34 34
 class PublicKeyTokenProvider implements IProvider {
35
-	/** @var PublicKeyTokenMapper */
36
-	private $mapper;
37
-
38
-	/** @var ICrypto */
39
-	private $crypto;
40
-
41
-	/** @var IConfig */
42
-	private $config;
43
-
44
-	/** @var ILogger $logger */
45
-	private $logger;
46
-
47
-	/** @var ITimeFactory $time */
48
-	private $time;
49
-
50
-	public function __construct(PublicKeyTokenMapper $mapper,
51
-								ICrypto $crypto,
52
-								IConfig $config,
53
-								ILogger $logger,
54
-								ITimeFactory $time) {
55
-		$this->mapper = $mapper;
56
-		$this->crypto = $crypto;
57
-		$this->config = $config;
58
-		$this->logger = $logger;
59
-		$this->time = $time;
60
-	}
61
-
62
-	public function generateToken(string $token,
63
-								  string $uid,
64
-								  string $loginName,
65
-								  $password,
66
-								  string $name,
67
-								  int $type = IToken::TEMPORARY_TOKEN,
68
-								  int $remember = IToken::DO_NOT_REMEMBER): IToken {
69
-		$dbToken = $this->newToken($token, $uid, $loginName, $password, $name, $type, $remember);
70
-
71
-		$this->mapper->insert($dbToken);
72
-
73
-		return $dbToken;
74
-	}
75
-
76
-	public function getToken(string $tokenId): IToken {
77
-		try {
78
-			$token = $this->mapper->getToken($this->hashToken($tokenId));
79
-		} catch (DoesNotExistException $ex) {
80
-			throw new InvalidTokenException();
81
-		}
82
-
83
-		if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
84
-			throw new ExpiredTokenException($token);
85
-		}
86
-
87
-		return $token;
88
-	}
89
-
90
-	public function getTokenById(int $tokenId): IToken {
91
-		try {
92
-			$token = $this->mapper->getTokenById($tokenId);
93
-		} catch (DoesNotExistException $ex) {
94
-			throw new InvalidTokenException();
95
-		}
96
-
97
-		if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
98
-			throw new ExpiredTokenException($token);
99
-		}
100
-
101
-		return $token;
102
-	}
103
-
104
-	public function renewSessionToken(string $oldSessionId, string $sessionId) {
105
-		$token = $this->getToken($oldSessionId);
106
-
107
-		if (!($token instanceof PublicKeyToken)) {
108
-			throw new InvalidTokenException();
109
-		}
110
-
111
-		$password = null;
112
-		if (!is_null($token->getPassword())) {
113
-			$privateKey = $this->decrypt($token->getPrivateKey(), $oldSessionId);
114
-			$password = $this->decryptPassword($token->getPassword(), $privateKey);
115
-		}
116
-
117
-		$this->generateToken(
118
-			$sessionId,
119
-			$token->getUID(),
120
-			$token->getLoginName(),
121
-			$password,
122
-			$token->getName(),
123
-			IToken::TEMPORARY_TOKEN,
124
-			$token->getRemember()
125
-		);
126
-
127
-		$this->mapper->delete($token);
128
-	}
129
-
130
-	public function invalidateToken(string $token) {
131
-		$this->mapper->invalidate($this->hashToken($token));
132
-	}
133
-
134
-	public function invalidateTokenById(string $uid, int $id) {
135
-		$this->mapper->deleteById($uid, $id);
136
-	}
137
-
138
-	public function invalidateOldTokens() {
139
-		$olderThan = $this->time->getTime() - (int) $this->config->getSystemValue('session_lifetime', 60 * 60 * 24);
140
-		$this->logger->debug('Invalidating session tokens older than ' . date('c', $olderThan), ['app' => 'cron']);
141
-		$this->mapper->invalidateOld($olderThan, IToken::DO_NOT_REMEMBER);
142
-		$rememberThreshold = $this->time->getTime() - (int) $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
143
-		$this->logger->debug('Invalidating remembered session tokens older than ' . date('c', $rememberThreshold), ['app' => 'cron']);
144
-		$this->mapper->invalidateOld($rememberThreshold, IToken::REMEMBER);
145
-	}
146
-
147
-	public function updateToken(IToken $token) {
148
-		if (!($token instanceof PublicKeyToken)) {
149
-			throw new InvalidTokenException();
150
-		}
151
-		$this->mapper->update($token);
152
-	}
153
-
154
-	public function updateTokenActivity(IToken $token) {
155
-		if (!($token instanceof PublicKeyToken)) {
156
-			throw new InvalidTokenException();
157
-		}
158
-		/** @var DefaultToken $token */
159
-		$now = $this->time->getTime();
160
-		if ($token->getLastActivity() < ($now - 60)) {
161
-			// Update token only once per minute
162
-			$token->setLastActivity($now);
163
-			$this->mapper->update($token);
164
-		}
165
-	}
166
-
167
-	public function getTokenByUser(string $uid): array {
168
-		return $this->mapper->getTokenByUser($uid);
169
-	}
170
-
171
-	public function getPassword(IToken $token, string $tokenId): string {
172
-		if (!($token instanceof PublicKeyToken)) {
173
-			throw new InvalidTokenException();
174
-		}
175
-
176
-		if ($token->getPassword() === null) {
177
-			throw new PasswordlessTokenException();
178
-		}
179
-
180
-		// Decrypt private key with tokenId
181
-		$privateKey = $this->decrypt($token->getPrivateKey(), $tokenId);
182
-
183
-		// Decrypt password with private key
184
-		return $this->decryptPassword($token->getPassword(), $privateKey);
185
-	}
186
-
187
-	public function setPassword(IToken $token, string $tokenId, string $password) {
188
-		if (!($token instanceof PublicKeyToken)) {
189
-			throw new InvalidTokenException();
190
-		}
191
-
192
-		// When changing passwords all temp tokens are deleted
193
-		$this->mapper->deleteTempToken($token);
194
-
195
-		// Update the password for all tokens
196
-		$tokens = $this->mapper->getTokenByUser($token->getUID());
197
-		foreach ($tokens as $t) {
198
-			$publicKey = $t->getPublicKey();
199
-			$t->setPassword($this->encryptPassword($password, $publicKey));
200
-			$this->updateToken($t);
201
-		}
202
-	}
203
-
204
-	public function rotate(IToken $token, string $oldTokenId, string $newTokenId): IToken {
205
-		if (!($token instanceof PublicKeyToken)) {
206
-			throw new InvalidTokenException();
207
-		}
208
-
209
-		// Decrypt private key with oldTokenId
210
-		$privateKey = $this->decrypt($token->getPrivateKey(), $oldTokenId);
211
-		// Encrypt with the new token
212
-		$token->setPrivateKey($this->encrypt($privateKey, $newTokenId));
213
-
214
-		$token->setToken($this->hashToken($newTokenId));
215
-		$this->updateToken($token);
216
-
217
-		return $token;
218
-	}
219
-
220
-	private function encrypt(string $plaintext, string $token): string {
221
-		$secret = $this->config->getSystemValue('secret');
222
-		return $this->crypto->encrypt($plaintext, $token . $secret);
223
-	}
224
-
225
-	/**
226
-	 * @throws InvalidTokenException
227
-	 */
228
-	private function decrypt(string $cipherText, string $token): string {
229
-		$secret = $this->config->getSystemValue('secret');
230
-		try {
231
-			return $this->crypto->decrypt($cipherText, $token . $secret);
232
-		} catch (\Exception $ex) {
233
-			// Delete the invalid token
234
-			$this->invalidateToken($token);
235
-			throw new InvalidTokenException();
236
-		}
237
-	}
238
-
239
-	private function encryptPassword(string $password, string $publicKey): string {
240
-		openssl_public_encrypt($password, $encryptedPassword, $publicKey, OPENSSL_PKCS1_OAEP_PADDING);
241
-		$encryptedPassword = base64_encode($encryptedPassword);
242
-
243
-		return $encryptedPassword;
244
-	}
245
-
246
-	private function decryptPassword(string $encryptedPassword, string $privateKey): string {
247
-		$encryptedPassword = base64_decode($encryptedPassword);
248
-		openssl_private_decrypt($encryptedPassword, $password, $privateKey, OPENSSL_PKCS1_OAEP_PADDING);
249
-
250
-		return $password;
251
-	}
252
-
253
-	private function hashToken(string $token): string {
254
-		$secret = $this->config->getSystemValue('secret');
255
-		return hash('sha512', $token . $secret);
256
-	}
257
-
258
-	/**
259
-	 * Convert a DefaultToken to a publicKeyToken
260
-	 * This will also be updated directly in the Database
261
-	 */
262
-	public function convertToken(DefaultToken $defaultToken, string $token, $password): PublicKeyToken {
263
-		$pkToken = $this->newToken(
264
-			$token,
265
-			$defaultToken->getUID(),
266
-			$defaultToken->getLoginName(),
267
-			$password,
268
-			$defaultToken->getName(),
269
-			$defaultToken->getType(),
270
-			$defaultToken->getRemember()
271
-		);
272
-
273
-		$pkToken->setExpires($defaultToken->getExpires());
274
-		$pkToken->setId($defaultToken->getId());
275
-
276
-		return $this->mapper->update($pkToken);
277
-	}
278
-
279
-	private function newToken(string $token,
280
-							  string $uid,
281
-							  string $loginName,
282
-							  $password,
283
-							  string $name,
284
-							  int $type,
285
-							  int $remember): PublicKeyToken {
286
-		$dbToken = new PublicKeyToken();
287
-		$dbToken->setUid($uid);
288
-		$dbToken->setLoginName($loginName);
289
-
290
-		$config = array_merge([
291
-			'digest_alg' => 'sha512',
292
-			'private_key_bits' => 2048,
293
-		], $this->config->getSystemValue('openssl', []));
294
-
295
-		// Generate new key
296
-		$res = openssl_pkey_new($config);
297
-		openssl_pkey_export($res, $privateKey);
298
-
299
-		// Extract the public key from $res to $pubKey
300
-		$publicKey = openssl_pkey_get_details($res);
301
-		$publicKey = $publicKey['key'];
302
-
303
-		$dbToken->setPublicKey($publicKey);
304
-		$dbToken->setPrivateKey($this->encrypt($privateKey, $token));
305
-
306
-		if (!is_null($password)) {
307
-			$dbToken->setPassword($this->encryptPassword($password, $publicKey));
308
-		}
309
-
310
-		$dbToken->setName($name);
311
-		$dbToken->setToken($this->hashToken($token));
312
-		$dbToken->setType($type);
313
-		$dbToken->setRemember($remember);
314
-		$dbToken->setLastActivity($this->time->getTime());
315
-		$dbToken->setLastCheck($this->time->getTime());
316
-		$dbToken->setVersion(PublicKeyToken::VERSION);
317
-
318
-		return $dbToken;
319
-	}
320
-
321
-	public function markPasswordInvalid(IToken $token, string $tokenId) {
322
-		if (!($token instanceof PublicKeyToken)) {
323
-			throw new InvalidTokenException();
324
-		}
325
-
326
-		$token->setPasswordInvalid(true);
327
-		$this->mapper->update($token);
328
-	}
329
-
330
-	public function updatePasswords(string $uid, string $password) {
331
-		if (!$this->mapper->hasExpiredTokens($uid)) {
332
-			// Nothing to do here
333
-			return;
334
-		}
335
-
336
-		// Update the password for all tokens
337
-		$tokens = $this->mapper->getTokenByUser($uid);
338
-		foreach ($tokens as $t) {
339
-			$publicKey = $t->getPublicKey();
340
-			$t->setPassword($this->encryptPassword($password, $publicKey));
341
-			$this->updateToken($t);
342
-		}
343
-	}
35
+    /** @var PublicKeyTokenMapper */
36
+    private $mapper;
37
+
38
+    /** @var ICrypto */
39
+    private $crypto;
40
+
41
+    /** @var IConfig */
42
+    private $config;
43
+
44
+    /** @var ILogger $logger */
45
+    private $logger;
46
+
47
+    /** @var ITimeFactory $time */
48
+    private $time;
49
+
50
+    public function __construct(PublicKeyTokenMapper $mapper,
51
+                                ICrypto $crypto,
52
+                                IConfig $config,
53
+                                ILogger $logger,
54
+                                ITimeFactory $time) {
55
+        $this->mapper = $mapper;
56
+        $this->crypto = $crypto;
57
+        $this->config = $config;
58
+        $this->logger = $logger;
59
+        $this->time = $time;
60
+    }
61
+
62
+    public function generateToken(string $token,
63
+                                    string $uid,
64
+                                    string $loginName,
65
+                                    $password,
66
+                                    string $name,
67
+                                    int $type = IToken::TEMPORARY_TOKEN,
68
+                                    int $remember = IToken::DO_NOT_REMEMBER): IToken {
69
+        $dbToken = $this->newToken($token, $uid, $loginName, $password, $name, $type, $remember);
70
+
71
+        $this->mapper->insert($dbToken);
72
+
73
+        return $dbToken;
74
+    }
75
+
76
+    public function getToken(string $tokenId): IToken {
77
+        try {
78
+            $token = $this->mapper->getToken($this->hashToken($tokenId));
79
+        } catch (DoesNotExistException $ex) {
80
+            throw new InvalidTokenException();
81
+        }
82
+
83
+        if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
84
+            throw new ExpiredTokenException($token);
85
+        }
86
+
87
+        return $token;
88
+    }
89
+
90
+    public function getTokenById(int $tokenId): IToken {
91
+        try {
92
+            $token = $this->mapper->getTokenById($tokenId);
93
+        } catch (DoesNotExistException $ex) {
94
+            throw new InvalidTokenException();
95
+        }
96
+
97
+        if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
98
+            throw new ExpiredTokenException($token);
99
+        }
100
+
101
+        return $token;
102
+    }
103
+
104
+    public function renewSessionToken(string $oldSessionId, string $sessionId) {
105
+        $token = $this->getToken($oldSessionId);
106
+
107
+        if (!($token instanceof PublicKeyToken)) {
108
+            throw new InvalidTokenException();
109
+        }
110
+
111
+        $password = null;
112
+        if (!is_null($token->getPassword())) {
113
+            $privateKey = $this->decrypt($token->getPrivateKey(), $oldSessionId);
114
+            $password = $this->decryptPassword($token->getPassword(), $privateKey);
115
+        }
116
+
117
+        $this->generateToken(
118
+            $sessionId,
119
+            $token->getUID(),
120
+            $token->getLoginName(),
121
+            $password,
122
+            $token->getName(),
123
+            IToken::TEMPORARY_TOKEN,
124
+            $token->getRemember()
125
+        );
126
+
127
+        $this->mapper->delete($token);
128
+    }
129
+
130
+    public function invalidateToken(string $token) {
131
+        $this->mapper->invalidate($this->hashToken($token));
132
+    }
133
+
134
+    public function invalidateTokenById(string $uid, int $id) {
135
+        $this->mapper->deleteById($uid, $id);
136
+    }
137
+
138
+    public function invalidateOldTokens() {
139
+        $olderThan = $this->time->getTime() - (int) $this->config->getSystemValue('session_lifetime', 60 * 60 * 24);
140
+        $this->logger->debug('Invalidating session tokens older than ' . date('c', $olderThan), ['app' => 'cron']);
141
+        $this->mapper->invalidateOld($olderThan, IToken::DO_NOT_REMEMBER);
142
+        $rememberThreshold = $this->time->getTime() - (int) $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
143
+        $this->logger->debug('Invalidating remembered session tokens older than ' . date('c', $rememberThreshold), ['app' => 'cron']);
144
+        $this->mapper->invalidateOld($rememberThreshold, IToken::REMEMBER);
145
+    }
146
+
147
+    public function updateToken(IToken $token) {
148
+        if (!($token instanceof PublicKeyToken)) {
149
+            throw new InvalidTokenException();
150
+        }
151
+        $this->mapper->update($token);
152
+    }
153
+
154
+    public function updateTokenActivity(IToken $token) {
155
+        if (!($token instanceof PublicKeyToken)) {
156
+            throw new InvalidTokenException();
157
+        }
158
+        /** @var DefaultToken $token */
159
+        $now = $this->time->getTime();
160
+        if ($token->getLastActivity() < ($now - 60)) {
161
+            // Update token only once per minute
162
+            $token->setLastActivity($now);
163
+            $this->mapper->update($token);
164
+        }
165
+    }
166
+
167
+    public function getTokenByUser(string $uid): array {
168
+        return $this->mapper->getTokenByUser($uid);
169
+    }
170
+
171
+    public function getPassword(IToken $token, string $tokenId): string {
172
+        if (!($token instanceof PublicKeyToken)) {
173
+            throw new InvalidTokenException();
174
+        }
175
+
176
+        if ($token->getPassword() === null) {
177
+            throw new PasswordlessTokenException();
178
+        }
179
+
180
+        // Decrypt private key with tokenId
181
+        $privateKey = $this->decrypt($token->getPrivateKey(), $tokenId);
182
+
183
+        // Decrypt password with private key
184
+        return $this->decryptPassword($token->getPassword(), $privateKey);
185
+    }
186
+
187
+    public function setPassword(IToken $token, string $tokenId, string $password) {
188
+        if (!($token instanceof PublicKeyToken)) {
189
+            throw new InvalidTokenException();
190
+        }
191
+
192
+        // When changing passwords all temp tokens are deleted
193
+        $this->mapper->deleteTempToken($token);
194
+
195
+        // Update the password for all tokens
196
+        $tokens = $this->mapper->getTokenByUser($token->getUID());
197
+        foreach ($tokens as $t) {
198
+            $publicKey = $t->getPublicKey();
199
+            $t->setPassword($this->encryptPassword($password, $publicKey));
200
+            $this->updateToken($t);
201
+        }
202
+    }
203
+
204
+    public function rotate(IToken $token, string $oldTokenId, string $newTokenId): IToken {
205
+        if (!($token instanceof PublicKeyToken)) {
206
+            throw new InvalidTokenException();
207
+        }
208
+
209
+        // Decrypt private key with oldTokenId
210
+        $privateKey = $this->decrypt($token->getPrivateKey(), $oldTokenId);
211
+        // Encrypt with the new token
212
+        $token->setPrivateKey($this->encrypt($privateKey, $newTokenId));
213
+
214
+        $token->setToken($this->hashToken($newTokenId));
215
+        $this->updateToken($token);
216
+
217
+        return $token;
218
+    }
219
+
220
+    private function encrypt(string $plaintext, string $token): string {
221
+        $secret = $this->config->getSystemValue('secret');
222
+        return $this->crypto->encrypt($plaintext, $token . $secret);
223
+    }
224
+
225
+    /**
226
+     * @throws InvalidTokenException
227
+     */
228
+    private function decrypt(string $cipherText, string $token): string {
229
+        $secret = $this->config->getSystemValue('secret');
230
+        try {
231
+            return $this->crypto->decrypt($cipherText, $token . $secret);
232
+        } catch (\Exception $ex) {
233
+            // Delete the invalid token
234
+            $this->invalidateToken($token);
235
+            throw new InvalidTokenException();
236
+        }
237
+    }
238
+
239
+    private function encryptPassword(string $password, string $publicKey): string {
240
+        openssl_public_encrypt($password, $encryptedPassword, $publicKey, OPENSSL_PKCS1_OAEP_PADDING);
241
+        $encryptedPassword = base64_encode($encryptedPassword);
242
+
243
+        return $encryptedPassword;
244
+    }
245
+
246
+    private function decryptPassword(string $encryptedPassword, string $privateKey): string {
247
+        $encryptedPassword = base64_decode($encryptedPassword);
248
+        openssl_private_decrypt($encryptedPassword, $password, $privateKey, OPENSSL_PKCS1_OAEP_PADDING);
249
+
250
+        return $password;
251
+    }
252
+
253
+    private function hashToken(string $token): string {
254
+        $secret = $this->config->getSystemValue('secret');
255
+        return hash('sha512', $token . $secret);
256
+    }
257
+
258
+    /**
259
+     * Convert a DefaultToken to a publicKeyToken
260
+     * This will also be updated directly in the Database
261
+     */
262
+    public function convertToken(DefaultToken $defaultToken, string $token, $password): PublicKeyToken {
263
+        $pkToken = $this->newToken(
264
+            $token,
265
+            $defaultToken->getUID(),
266
+            $defaultToken->getLoginName(),
267
+            $password,
268
+            $defaultToken->getName(),
269
+            $defaultToken->getType(),
270
+            $defaultToken->getRemember()
271
+        );
272
+
273
+        $pkToken->setExpires($defaultToken->getExpires());
274
+        $pkToken->setId($defaultToken->getId());
275
+
276
+        return $this->mapper->update($pkToken);
277
+    }
278
+
279
+    private function newToken(string $token,
280
+                                string $uid,
281
+                                string $loginName,
282
+                                $password,
283
+                                string $name,
284
+                                int $type,
285
+                                int $remember): PublicKeyToken {
286
+        $dbToken = new PublicKeyToken();
287
+        $dbToken->setUid($uid);
288
+        $dbToken->setLoginName($loginName);
289
+
290
+        $config = array_merge([
291
+            'digest_alg' => 'sha512',
292
+            'private_key_bits' => 2048,
293
+        ], $this->config->getSystemValue('openssl', []));
294
+
295
+        // Generate new key
296
+        $res = openssl_pkey_new($config);
297
+        openssl_pkey_export($res, $privateKey);
298
+
299
+        // Extract the public key from $res to $pubKey
300
+        $publicKey = openssl_pkey_get_details($res);
301
+        $publicKey = $publicKey['key'];
302
+
303
+        $dbToken->setPublicKey($publicKey);
304
+        $dbToken->setPrivateKey($this->encrypt($privateKey, $token));
305
+
306
+        if (!is_null($password)) {
307
+            $dbToken->setPassword($this->encryptPassword($password, $publicKey));
308
+        }
309
+
310
+        $dbToken->setName($name);
311
+        $dbToken->setToken($this->hashToken($token));
312
+        $dbToken->setType($type);
313
+        $dbToken->setRemember($remember);
314
+        $dbToken->setLastActivity($this->time->getTime());
315
+        $dbToken->setLastCheck($this->time->getTime());
316
+        $dbToken->setVersion(PublicKeyToken::VERSION);
317
+
318
+        return $dbToken;
319
+    }
320
+
321
+    public function markPasswordInvalid(IToken $token, string $tokenId) {
322
+        if (!($token instanceof PublicKeyToken)) {
323
+            throw new InvalidTokenException();
324
+        }
325
+
326
+        $token->setPasswordInvalid(true);
327
+        $this->mapper->update($token);
328
+    }
329
+
330
+    public function updatePasswords(string $uid, string $password) {
331
+        if (!$this->mapper->hasExpiredTokens($uid)) {
332
+            // Nothing to do here
333
+            return;
334
+        }
335
+
336
+        // Update the password for all tokens
337
+        $tokens = $this->mapper->getTokenByUser($uid);
338
+        foreach ($tokens as $t) {
339
+            $publicKey = $t->getPublicKey();
340
+            $t->setPassword($this->encryptPassword($password, $publicKey));
341
+            $this->updateToken($t);
342
+        }
343
+    }
344 344
 
345 345
 
346 346
 }
Please login to merge, or discard this patch.
lib/private/User/Session.php 1 patch
Indentation   +867 added lines, -867 removed lines patch added patch discarded remove patch
@@ -86,873 +86,873 @@
 block discarded – undo
86 86
  */
87 87
 class Session implements IUserSession, Emitter {
88 88
 
89
-	/** @var Manager|PublicEmitter $manager */
90
-	private $manager;
91
-
92
-	/** @var ISession $session */
93
-	private $session;
94
-
95
-	/** @var ITimeFactory */
96
-	private $timeFactory;
97
-
98
-	/** @var IProvider */
99
-	private $tokenProvider;
100
-
101
-	/** @var IConfig */
102
-	private $config;
103
-
104
-	/** @var User $activeUser */
105
-	protected $activeUser;
106
-
107
-	/** @var ISecureRandom */
108
-	private $random;
109
-
110
-	/** @var ILockdownManager  */
111
-	private $lockdownManager;
112
-
113
-	/** @var ILogger */
114
-	private $logger;
115
-
116
-	/**
117
-	 * @param Manager $manager
118
-	 * @param ISession $session
119
-	 * @param ITimeFactory $timeFactory
120
-	 * @param IProvider $tokenProvider
121
-	 * @param IConfig $config
122
-	 * @param ISecureRandom $random
123
-	 * @param ILockdownManager $lockdownManager
124
-	 * @param ILogger $logger
125
-	 */
126
-	public function __construct(Manager $manager,
127
-								ISession $session,
128
-								ITimeFactory $timeFactory,
129
-								$tokenProvider,
130
-								IConfig $config,
131
-								ISecureRandom $random,
132
-								ILockdownManager $lockdownManager,
133
-								ILogger $logger) {
134
-		$this->manager = $manager;
135
-		$this->session = $session;
136
-		$this->timeFactory = $timeFactory;
137
-		$this->tokenProvider = $tokenProvider;
138
-		$this->config = $config;
139
-		$this->random = $random;
140
-		$this->lockdownManager = $lockdownManager;
141
-		$this->logger = $logger;
142
-	}
143
-
144
-	/**
145
-	 * @param IProvider $provider
146
-	 */
147
-	public function setTokenProvider(IProvider $provider) {
148
-		$this->tokenProvider = $provider;
149
-	}
150
-
151
-	/**
152
-	 * @param string $scope
153
-	 * @param string $method
154
-	 * @param callable $callback
155
-	 */
156
-	public function listen($scope, $method, callable $callback) {
157
-		$this->manager->listen($scope, $method, $callback);
158
-	}
159
-
160
-	/**
161
-	 * @param string $scope optional
162
-	 * @param string $method optional
163
-	 * @param callable $callback optional
164
-	 */
165
-	public function removeListener($scope = null, $method = null, callable $callback = null) {
166
-		$this->manager->removeListener($scope, $method, $callback);
167
-	}
168
-
169
-	/**
170
-	 * get the manager object
171
-	 *
172
-	 * @return Manager|PublicEmitter
173
-	 */
174
-	public function getManager() {
175
-		return $this->manager;
176
-	}
177
-
178
-	/**
179
-	 * get the session object
180
-	 *
181
-	 * @return ISession
182
-	 */
183
-	public function getSession() {
184
-		return $this->session;
185
-	}
186
-
187
-	/**
188
-	 * set the session object
189
-	 *
190
-	 * @param ISession $session
191
-	 */
192
-	public function setSession(ISession $session) {
193
-		if ($this->session instanceof ISession) {
194
-			$this->session->close();
195
-		}
196
-		$this->session = $session;
197
-		$this->activeUser = null;
198
-	}
199
-
200
-	/**
201
-	 * set the currently active user
202
-	 *
203
-	 * @param IUser|null $user
204
-	 */
205
-	public function setUser($user) {
206
-		if (is_null($user)) {
207
-			$this->session->remove('user_id');
208
-		} else {
209
-			$this->session->set('user_id', $user->getUID());
210
-		}
211
-		$this->activeUser = $user;
212
-	}
213
-
214
-	/**
215
-	 * get the current active user
216
-	 *
217
-	 * @return IUser|null Current user, otherwise null
218
-	 */
219
-	public function getUser() {
220
-		// FIXME: This is a quick'n dirty work-around for the incognito mode as
221
-		// described at https://github.com/owncloud/core/pull/12912#issuecomment-67391155
222
-		if (OC_User::isIncognitoMode()) {
223
-			return null;
224
-		}
225
-		if (is_null($this->activeUser)) {
226
-			$uid = $this->session->get('user_id');
227
-			if (is_null($uid)) {
228
-				return null;
229
-			}
230
-			$this->activeUser = $this->manager->get($uid);
231
-			if (is_null($this->activeUser)) {
232
-				return null;
233
-			}
234
-			$this->validateSession();
235
-		}
236
-		return $this->activeUser;
237
-	}
238
-
239
-	/**
240
-	 * Validate whether the current session is valid
241
-	 *
242
-	 * - For token-authenticated clients, the token validity is checked
243
-	 * - For browsers, the session token validity is checked
244
-	 */
245
-	protected function validateSession() {
246
-		$token = null;
247
-		$appPassword = $this->session->get('app_password');
248
-
249
-		if (is_null($appPassword)) {
250
-			try {
251
-				$token = $this->session->getId();
252
-			} catch (SessionNotAvailableException $ex) {
253
-				return;
254
-			}
255
-		} else {
256
-			$token = $appPassword;
257
-		}
258
-
259
-		if (!$this->validateToken($token)) {
260
-			// Session was invalidated
261
-			$this->logout();
262
-		}
263
-	}
264
-
265
-	/**
266
-	 * Checks whether the user is logged in
267
-	 *
268
-	 * @return bool if logged in
269
-	 */
270
-	public function isLoggedIn() {
271
-		$user = $this->getUser();
272
-		if (is_null($user)) {
273
-			return false;
274
-		}
275
-
276
-		return $user->isEnabled();
277
-	}
278
-
279
-	/**
280
-	 * set the login name
281
-	 *
282
-	 * @param string|null $loginName for the logged in user
283
-	 */
284
-	public function setLoginName($loginName) {
285
-		if (is_null($loginName)) {
286
-			$this->session->remove('loginname');
287
-		} else {
288
-			$this->session->set('loginname', $loginName);
289
-		}
290
-	}
291
-
292
-	/**
293
-	 * get the login name of the current user
294
-	 *
295
-	 * @return string
296
-	 */
297
-	public function getLoginName() {
298
-		if ($this->activeUser) {
299
-			return $this->session->get('loginname');
300
-		}
301
-
302
-		$uid = $this->session->get('user_id');
303
-		if ($uid) {
304
-			$this->activeUser = $this->manager->get($uid);
305
-			return $this->session->get('loginname');
306
-		}
307
-
308
-		return null;
309
-	}
310
-
311
-	/**
312
-	 * set the token id
313
-	 *
314
-	 * @param int|null $token that was used to log in
315
-	 */
316
-	protected function setToken($token) {
317
-		if ($token === null) {
318
-			$this->session->remove('token-id');
319
-		} else {
320
-			$this->session->set('token-id', $token);
321
-		}
322
-	}
323
-
324
-	/**
325
-	 * try to log in with the provided credentials
326
-	 *
327
-	 * @param string $uid
328
-	 * @param string $password
329
-	 * @return boolean|null
330
-	 * @throws LoginException
331
-	 */
332
-	public function login($uid, $password) {
333
-		$this->session->regenerateId();
334
-		if ($this->validateToken($password, $uid)) {
335
-			return $this->loginWithToken($password);
336
-		}
337
-		return $this->loginWithPassword($uid, $password);
338
-	}
339
-
340
-	/**
341
-	 * @param IUser $user
342
-	 * @param array $loginDetails
343
-	 * @param bool $regenerateSessionId
344
-	 * @return true returns true if login successful or an exception otherwise
345
-	 * @throws LoginException
346
-	 */
347
-	public function completeLogin(IUser $user, array $loginDetails, $regenerateSessionId = true) {
348
-		if (!$user->isEnabled()) {
349
-			// disabled users can not log in
350
-			// injecting l10n does not work - there is a circular dependency between session and \OCP\L10N\IFactory
351
-			$message = \OC::$server->getL10N('lib')->t('User disabled');
352
-			throw new LoginException($message);
353
-		}
354
-
355
-		if($regenerateSessionId) {
356
-			$this->session->regenerateId();
357
-		}
358
-
359
-		$this->setUser($user);
360
-		$this->setLoginName($loginDetails['loginName']);
361
-
362
-		if(isset($loginDetails['token']) && $loginDetails['token'] instanceof IToken) {
363
-			$this->setToken($loginDetails['token']->getId());
364
-			$this->lockdownManager->setToken($loginDetails['token']);
365
-			$firstTimeLogin = false;
366
-		} else {
367
-			$this->setToken(null);
368
-			$firstTimeLogin = $user->updateLastLoginTimestamp();
369
-		}
370
-		$this->manager->emit('\OC\User', 'postLogin', [$user, $loginDetails['password']]);
371
-		if($this->isLoggedIn()) {
372
-			$this->prepareUserLogin($firstTimeLogin, $regenerateSessionId);
373
-			return true;
374
-		}
375
-
376
-		$message = \OC::$server->getL10N('lib')->t('Login canceled by app');
377
-		throw new LoginException($message);
378
-	}
379
-
380
-	/**
381
-	 * Tries to log in a client
382
-	 *
383
-	 * Checks token auth enforced
384
-	 * Checks 2FA enabled
385
-	 *
386
-	 * @param string $user
387
-	 * @param string $password
388
-	 * @param IRequest $request
389
-	 * @param OC\Security\Bruteforce\Throttler $throttler
390
-	 * @throws LoginException
391
-	 * @throws PasswordLoginForbiddenException
392
-	 * @return boolean
393
-	 */
394
-	public function logClientIn($user,
395
-								$password,
396
-								IRequest $request,
397
-								OC\Security\Bruteforce\Throttler $throttler) {
398
-		$currentDelay = $throttler->sleepDelay($request->getRemoteAddress(), 'login');
399
-
400
-		if ($this->manager instanceof PublicEmitter) {
401
-			$this->manager->emit('\OC\User', 'preLogin', array($user, $password));
402
-		}
403
-
404
-		$isTokenPassword = $this->isTokenPassword($password);
405
-		if (!$isTokenPassword && $this->isTokenAuthEnforced()) {
406
-			throw new PasswordLoginForbiddenException();
407
-		}
408
-		if (!$isTokenPassword && $this->isTwoFactorEnforced($user)) {
409
-			throw new PasswordLoginForbiddenException();
410
-		}
411
-
412
-		// Try to login with this username and password
413
-		if (!$this->login($user, $password) ) {
414
-
415
-			// Failed, maybe the user used their email address
416
-			$users = $this->manager->getByEmail($user);
417
-			if (!(\count($users) === 1 && $this->login($users[0]->getUID(), $password))) {
418
-
419
-				$this->logger->warning('Login failed: \'' . $user . '\' (Remote IP: \'' . \OC::$server->getRequest()->getRemoteAddress() . '\')', ['app' => 'core']);
420
-
421
-				$throttler->registerAttempt('login', $request->getRemoteAddress(), ['uid' => $user]);
422
-				if ($currentDelay === 0) {
423
-					$throttler->sleepDelay($request->getRemoteAddress(), 'login');
424
-				}
425
-				return false;
426
-			}
427
-		}
428
-
429
-		if ($isTokenPassword) {
430
-			$this->session->set('app_password', $password);
431
-		} else if($this->supportsCookies($request)) {
432
-			// Password login, but cookies supported -> create (browser) session token
433
-			$this->createSessionToken($request, $this->getUser()->getUID(), $user, $password);
434
-		}
435
-
436
-		return true;
437
-	}
438
-
439
-	protected function supportsCookies(IRequest $request) {
440
-		if (!is_null($request->getCookie('cookie_test'))) {
441
-			return true;
442
-		}
443
-		setcookie('cookie_test', 'test', $this->timeFactory->getTime() + 3600);
444
-		return false;
445
-	}
446
-
447
-	private function isTokenAuthEnforced() {
448
-		return $this->config->getSystemValue('token_auth_enforced', false);
449
-	}
450
-
451
-	protected function isTwoFactorEnforced($username) {
452
-		Util::emitHook(
453
-			'\OCA\Files_Sharing\API\Server2Server',
454
-			'preLoginNameUsedAsUserName',
455
-			array('uid' => &$username)
456
-		);
457
-		$user = $this->manager->get($username);
458
-		if (is_null($user)) {
459
-			$users = $this->manager->getByEmail($username);
460
-			if (empty($users)) {
461
-				return false;
462
-			}
463
-			if (count($users) !== 1) {
464
-				return true;
465
-			}
466
-			$user = $users[0];
467
-		}
468
-		// DI not possible due to cyclic dependencies :'-/
469
-		return OC::$server->getTwoFactorAuthManager()->isTwoFactorAuthenticated($user);
470
-	}
471
-
472
-	/**
473
-	 * Check if the given 'password' is actually a device token
474
-	 *
475
-	 * @param string $password
476
-	 * @return boolean
477
-	 */
478
-	public function isTokenPassword($password) {
479
-		try {
480
-			$this->tokenProvider->getToken($password);
481
-			return true;
482
-		} catch (InvalidTokenException $ex) {
483
-			return false;
484
-		}
485
-	}
486
-
487
-	protected function prepareUserLogin($firstTimeLogin, $refreshCsrfToken = true) {
488
-		if ($refreshCsrfToken) {
489
-			// TODO: mock/inject/use non-static
490
-			// Refresh the token
491
-			\OC::$server->getCsrfTokenManager()->refreshToken();
492
-		}
493
-
494
-		//we need to pass the user name, which may differ from login name
495
-		$user = $this->getUser()->getUID();
496
-		OC_Util::setupFS($user);
497
-
498
-		if ($firstTimeLogin) {
499
-			// TODO: lock necessary?
500
-			//trigger creation of user home and /files folder
501
-			$userFolder = \OC::$server->getUserFolder($user);
502
-
503
-			try {
504
-				// copy skeleton
505
-				\OC_Util::copySkeleton($user, $userFolder);
506
-			} catch (NotPermittedException $ex) {
507
-				// read only uses
508
-			}
509
-
510
-			// trigger any other initialization
511
-			\OC::$server->getEventDispatcher()->dispatch(IUser::class . '::firstLogin', new GenericEvent($this->getUser()));
512
-		}
513
-	}
514
-
515
-	/**
516
-	 * Tries to login the user with HTTP Basic Authentication
517
-	 *
518
-	 * @todo do not allow basic auth if the user is 2FA enforced
519
-	 * @param IRequest $request
520
-	 * @param OC\Security\Bruteforce\Throttler $throttler
521
-	 * @return boolean if the login was successful
522
-	 */
523
-	public function tryBasicAuthLogin(IRequest $request,
524
-									  OC\Security\Bruteforce\Throttler $throttler) {
525
-		if (!empty($request->server['PHP_AUTH_USER']) && !empty($request->server['PHP_AUTH_PW'])) {
526
-			try {
527
-				if ($this->logClientIn($request->server['PHP_AUTH_USER'], $request->server['PHP_AUTH_PW'], $request, $throttler)) {
528
-					/**
529
-					 * Add DAV authenticated. This should in an ideal world not be
530
-					 * necessary but the iOS App reads cookies from anywhere instead
531
-					 * only the DAV endpoint.
532
-					 * This makes sure that the cookies will be valid for the whole scope
533
-					 * @see https://github.com/owncloud/core/issues/22893
534
-					 */
535
-					$this->session->set(
536
-						Auth::DAV_AUTHENTICATED, $this->getUser()->getUID()
537
-					);
538
-
539
-					// Set the last-password-confirm session to make the sudo mode work
540
-					 $this->session->set('last-password-confirm', $this->timeFactory->getTime());
541
-
542
-					return true;
543
-				}
544
-			} catch (PasswordLoginForbiddenException $ex) {
545
-				// Nothing to do
546
-			}
547
-		}
548
-		return false;
549
-	}
550
-
551
-	/**
552
-	 * Log an user in via login name and password
553
-	 *
554
-	 * @param string $uid
555
-	 * @param string $password
556
-	 * @return boolean
557
-	 * @throws LoginException if an app canceld the login process or the user is not enabled
558
-	 */
559
-	private function loginWithPassword($uid, $password) {
560
-		$user = $this->manager->checkPasswordNoLogging($uid, $password);
561
-		if ($user === false) {
562
-			// Password check failed
563
-			return false;
564
-		}
565
-
566
-		return $this->completeLogin($user, ['loginName' => $uid, 'password' => $password], false);
567
-	}
568
-
569
-	/**
570
-	 * Log an user in with a given token (id)
571
-	 *
572
-	 * @param string $token
573
-	 * @return boolean
574
-	 * @throws LoginException if an app canceled the login process or the user is not enabled
575
-	 */
576
-	private function loginWithToken($token) {
577
-		try {
578
-			$dbToken = $this->tokenProvider->getToken($token);
579
-		} catch (InvalidTokenException $ex) {
580
-			return false;
581
-		}
582
-		$uid = $dbToken->getUID();
583
-
584
-		// When logging in with token, the password must be decrypted first before passing to login hook
585
-		$password = '';
586
-		try {
587
-			$password = $this->tokenProvider->getPassword($dbToken, $token);
588
-		} catch (PasswordlessTokenException $ex) {
589
-			// Ignore and use empty string instead
590
-		}
591
-
592
-		$this->manager->emit('\OC\User', 'preLogin', array($uid, $password));
593
-
594
-		$user = $this->manager->get($uid);
595
-		if (is_null($user)) {
596
-			// user does not exist
597
-			return false;
598
-		}
599
-
600
-		return $this->completeLogin(
601
-			$user,
602
-			[
603
-				'loginName' => $dbToken->getLoginName(),
604
-				'password' => $password,
605
-				'token' => $dbToken
606
-			],
607
-			false);
608
-	}
609
-
610
-	/**
611
-	 * Create a new session token for the given user credentials
612
-	 *
613
-	 * @param IRequest $request
614
-	 * @param string $uid user UID
615
-	 * @param string $loginName login name
616
-	 * @param string $password
617
-	 * @param int $remember
618
-	 * @return boolean
619
-	 */
620
-	public function createSessionToken(IRequest $request, $uid, $loginName, $password = null, $remember = IToken::DO_NOT_REMEMBER) {
621
-		if (is_null($this->manager->get($uid))) {
622
-			// User does not exist
623
-			return false;
624
-		}
625
-		$name = isset($request->server['HTTP_USER_AGENT']) ? $request->server['HTTP_USER_AGENT'] : 'unknown browser';
626
-		try {
627
-			$sessionId = $this->session->getId();
628
-			$pwd = $this->getPassword($password);
629
-			// Make sure the current sessionId has no leftover tokens
630
-			$this->tokenProvider->invalidateToken($sessionId);
631
-			$this->tokenProvider->generateToken($sessionId, $uid, $loginName, $pwd, $name, IToken::TEMPORARY_TOKEN, $remember);
632
-			return true;
633
-		} catch (SessionNotAvailableException $ex) {
634
-			// This can happen with OCC, where a memory session is used
635
-			// if a memory session is used, we shouldn't create a session token anyway
636
-			return false;
637
-		}
638
-	}
639
-
640
-	/**
641
-	 * Checks if the given password is a token.
642
-	 * If yes, the password is extracted from the token.
643
-	 * If no, the same password is returned.
644
-	 *
645
-	 * @param string $password either the login password or a device token
646
-	 * @return string|null the password or null if none was set in the token
647
-	 */
648
-	private function getPassword($password) {
649
-		if (is_null($password)) {
650
-			// This is surely no token ;-)
651
-			return null;
652
-		}
653
-		try {
654
-			$token = $this->tokenProvider->getToken($password);
655
-			try {
656
-				return $this->tokenProvider->getPassword($token, $password);
657
-			} catch (PasswordlessTokenException $ex) {
658
-				return null;
659
-			}
660
-		} catch (InvalidTokenException $ex) {
661
-			return $password;
662
-		}
663
-	}
664
-
665
-	/**
666
-	 * @param IToken $dbToken
667
-	 * @param string $token
668
-	 * @return boolean
669
-	 */
670
-	private function checkTokenCredentials(IToken $dbToken, $token) {
671
-		// Check whether login credentials are still valid and the user was not disabled
672
-		// This check is performed each 5 minutes
673
-		$lastCheck = $dbToken->getLastCheck() ? : 0;
674
-		$now = $this->timeFactory->getTime();
675
-		if ($lastCheck > ($now - 60 * 5)) {
676
-			// Checked performed recently, nothing to do now
677
-			return true;
678
-		}
679
-
680
-		try {
681
-			$pwd = $this->tokenProvider->getPassword($dbToken, $token);
682
-		} catch (InvalidTokenException $ex) {
683
-			// An invalid token password was used -> log user out
684
-			return false;
685
-		} catch (PasswordlessTokenException $ex) {
686
-			// Token has no password
687
-
688
-			if (!is_null($this->activeUser) && !$this->activeUser->isEnabled()) {
689
-				$this->tokenProvider->invalidateToken($token);
690
-				return false;
691
-			}
692
-
693
-			$dbToken->setLastCheck($now);
694
-			return true;
695
-		}
696
-
697
-		// Invalidate token if the user is no longer active
698
-		if (!is_null($this->activeUser) && !$this->activeUser->isEnabled()) {
699
-			$this->tokenProvider->invalidateToken($token);
700
-			return false;
701
-		}
702
-
703
-		// If the token password is no longer valid mark it as such
704
-		if ($this->manager->checkPassword($dbToken->getLoginName(), $pwd) === false) {
705
-			$this->tokenProvider->markPasswordInvalid($dbToken, $token);
706
-			// User is logged out
707
-			return false;
708
-		}
709
-
710
-		$dbToken->setLastCheck($now);
711
-		return true;
712
-	}
713
-
714
-	/**
715
-	 * Check if the given token exists and performs password/user-enabled checks
716
-	 *
717
-	 * Invalidates the token if checks fail
718
-	 *
719
-	 * @param string $token
720
-	 * @param string $user login name
721
-	 * @return boolean
722
-	 */
723
-	private function validateToken($token, $user = null) {
724
-		try {
725
-			$dbToken = $this->tokenProvider->getToken($token);
726
-		} catch (InvalidTokenException $ex) {
727
-			return false;
728
-		}
729
-
730
-		// Check if login names match
731
-		if (!is_null($user) && $dbToken->getLoginName() !== $user) {
732
-			// TODO: this makes it imposssible to use different login names on browser and client
733
-			// e.g. login by e-mail '[email protected]' on browser for generating the token will not
734
-			//      allow to use the client token with the login name 'user'.
735
-			return false;
736
-		}
737
-
738
-		if (!$this->checkTokenCredentials($dbToken, $token)) {
739
-			return false;
740
-		}
741
-
742
-		// Update token scope
743
-		$this->lockdownManager->setToken($dbToken);
744
-
745
-		$this->tokenProvider->updateTokenActivity($dbToken);
746
-
747
-		return true;
748
-	}
749
-
750
-	/**
751
-	 * Tries to login the user with auth token header
752
-	 *
753
-	 * @param IRequest $request
754
-	 * @todo check remember me cookie
755
-	 * @return boolean
756
-	 */
757
-	public function tryTokenLogin(IRequest $request) {
758
-		$authHeader = $request->getHeader('Authorization');
759
-		if (strpos($authHeader, 'Bearer ') === false) {
760
-			// No auth header, let's try session id
761
-			try {
762
-				$token = $this->session->getId();
763
-			} catch (SessionNotAvailableException $ex) {
764
-				return false;
765
-			}
766
-		} else {
767
-			$token = substr($authHeader, 7);
768
-		}
769
-
770
-		if (!$this->loginWithToken($token)) {
771
-			return false;
772
-		}
773
-		if(!$this->validateToken($token)) {
774
-			return false;
775
-		}
776
-		return true;
777
-	}
778
-
779
-	/**
780
-	 * perform login using the magic cookie (remember login)
781
-	 *
782
-	 * @param string $uid the username
783
-	 * @param string $currentToken
784
-	 * @param string $oldSessionId
785
-	 * @return bool
786
-	 */
787
-	public function loginWithCookie($uid, $currentToken, $oldSessionId) {
788
-		$this->session->regenerateId();
789
-		$this->manager->emit('\OC\User', 'preRememberedLogin', array($uid));
790
-		$user = $this->manager->get($uid);
791
-		if (is_null($user)) {
792
-			// user does not exist
793
-			return false;
794
-		}
795
-
796
-		// get stored tokens
797
-		$tokens = $this->config->getUserKeys($uid, 'login_token');
798
-		// test cookies token against stored tokens
799
-		if (!in_array($currentToken, $tokens, true)) {
800
-			return false;
801
-		}
802
-		// replace successfully used token with a new one
803
-		$this->config->deleteUserValue($uid, 'login_token', $currentToken);
804
-		$newToken = $this->random->generate(32);
805
-		$this->config->setUserValue($uid, 'login_token', $newToken, $this->timeFactory->getTime());
806
-
807
-		try {
808
-			$sessionId = $this->session->getId();
809
-			$this->tokenProvider->renewSessionToken($oldSessionId, $sessionId);
810
-		} catch (SessionNotAvailableException $ex) {
811
-			return false;
812
-		} catch (InvalidTokenException $ex) {
813
-			\OC::$server->getLogger()->warning('Renewing session token failed', ['app' => 'core']);
814
-			return false;
815
-		}
816
-
817
-		$this->setMagicInCookie($user->getUID(), $newToken);
818
-		$token = $this->tokenProvider->getToken($sessionId);
819
-
820
-		//login
821
-		$this->setUser($user);
822
-		$this->setLoginName($token->getLoginName());
823
-		$this->setToken($token->getId());
824
-		$this->lockdownManager->setToken($token);
825
-		$user->updateLastLoginTimestamp();
826
-		$password = null;
827
-		try {
828
-			$password = $this->tokenProvider->getPassword($token, $sessionId);
829
-		} catch (PasswordlessTokenException $ex) {
830
-			// Ignore
831
-		}
832
-		$this->manager->emit('\OC\User', 'postRememberedLogin', [$user, $password]);
833
-		return true;
834
-	}
835
-
836
-	/**
837
-	 * @param IUser $user
838
-	 */
839
-	public function createRememberMeToken(IUser $user) {
840
-		$token = $this->random->generate(32);
841
-		$this->config->setUserValue($user->getUID(), 'login_token', $token, $this->timeFactory->getTime());
842
-		$this->setMagicInCookie($user->getUID(), $token);
843
-	}
844
-
845
-	/**
846
-	 * logout the user from the session
847
-	 */
848
-	public function logout() {
849
-		$this->manager->emit('\OC\User', 'logout');
850
-		$user = $this->getUser();
851
-		if (!is_null($user)) {
852
-			try {
853
-				$this->tokenProvider->invalidateToken($this->session->getId());
854
-			} catch (SessionNotAvailableException $ex) {
855
-
856
-			}
857
-		}
858
-		$this->setUser(null);
859
-		$this->setLoginName(null);
860
-		$this->setToken(null);
861
-		$this->unsetMagicInCookie();
862
-		$this->session->clear();
863
-		$this->manager->emit('\OC\User', 'postLogout');
864
-	}
865
-
866
-	/**
867
-	 * Set cookie value to use in next page load
868
-	 *
869
-	 * @param string $username username to be set
870
-	 * @param string $token
871
-	 */
872
-	public function setMagicInCookie($username, $token) {
873
-		$secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
874
-		$webRoot = \OC::$WEBROOT;
875
-		if ($webRoot === '') {
876
-			$webRoot = '/';
877
-		}
878
-
879
-		$maxAge = $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
880
-		\OC\Http\CookieHelper::setCookie(
881
-			'nc_username',
882
-			$username,
883
-			$maxAge,
884
-			$webRoot,
885
-			'',
886
-			$secureCookie,
887
-			true,
888
-			\OC\Http\CookieHelper::SAMESITE_LAX
889
-		);
890
-		\OC\Http\CookieHelper::setCookie(
891
-			'nc_token',
892
-			$token,
893
-			$maxAge,
894
-			$webRoot,
895
-			'',
896
-			$secureCookie,
897
-			true,
898
-			\OC\Http\CookieHelper::SAMESITE_LAX
899
-		);
900
-		try {
901
-			\OC\Http\CookieHelper::setCookie(
902
-				'nc_session_id',
903
-				$this->session->getId(),
904
-				$maxAge,
905
-				$webRoot,
906
-				'',
907
-				$secureCookie,
908
-				true,
909
-				\OC\Http\CookieHelper::SAMESITE_LAX
910
-			);
911
-		} catch (SessionNotAvailableException $ex) {
912
-			// ignore
913
-		}
914
-	}
915
-
916
-	/**
917
-	 * Remove cookie for "remember username"
918
-	 */
919
-	public function unsetMagicInCookie() {
920
-		//TODO: DI for cookies and IRequest
921
-		$secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
922
-
923
-		unset($_COOKIE['nc_username']); //TODO: DI
924
-		unset($_COOKIE['nc_token']);
925
-		unset($_COOKIE['nc_session_id']);
926
-		setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
927
-		setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
928
-		setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
929
-		// old cookies might be stored under /webroot/ instead of /webroot
930
-		// and Firefox doesn't like it!
931
-		setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
932
-		setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
933
-		setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
934
-	}
935
-
936
-	/**
937
-	 * Update password of the browser session token if there is one
938
-	 *
939
-	 * @param string $password
940
-	 */
941
-	public function updateSessionTokenPassword($password) {
942
-		try {
943
-			$sessionId = $this->session->getId();
944
-			$token = $this->tokenProvider->getToken($sessionId);
945
-			$this->tokenProvider->setPassword($token, $sessionId, $password);
946
-		} catch (SessionNotAvailableException $ex) {
947
-			// Nothing to do
948
-		} catch (InvalidTokenException $ex) {
949
-			// Nothing to do
950
-		}
951
-	}
952
-
953
-	public function updateTokens(string $uid, string $password) {
954
-		$this->tokenProvider->updatePasswords($uid, $password);
955
-	}
89
+    /** @var Manager|PublicEmitter $manager */
90
+    private $manager;
91
+
92
+    /** @var ISession $session */
93
+    private $session;
94
+
95
+    /** @var ITimeFactory */
96
+    private $timeFactory;
97
+
98
+    /** @var IProvider */
99
+    private $tokenProvider;
100
+
101
+    /** @var IConfig */
102
+    private $config;
103
+
104
+    /** @var User $activeUser */
105
+    protected $activeUser;
106
+
107
+    /** @var ISecureRandom */
108
+    private $random;
109
+
110
+    /** @var ILockdownManager  */
111
+    private $lockdownManager;
112
+
113
+    /** @var ILogger */
114
+    private $logger;
115
+
116
+    /**
117
+     * @param Manager $manager
118
+     * @param ISession $session
119
+     * @param ITimeFactory $timeFactory
120
+     * @param IProvider $tokenProvider
121
+     * @param IConfig $config
122
+     * @param ISecureRandom $random
123
+     * @param ILockdownManager $lockdownManager
124
+     * @param ILogger $logger
125
+     */
126
+    public function __construct(Manager $manager,
127
+                                ISession $session,
128
+                                ITimeFactory $timeFactory,
129
+                                $tokenProvider,
130
+                                IConfig $config,
131
+                                ISecureRandom $random,
132
+                                ILockdownManager $lockdownManager,
133
+                                ILogger $logger) {
134
+        $this->manager = $manager;
135
+        $this->session = $session;
136
+        $this->timeFactory = $timeFactory;
137
+        $this->tokenProvider = $tokenProvider;
138
+        $this->config = $config;
139
+        $this->random = $random;
140
+        $this->lockdownManager = $lockdownManager;
141
+        $this->logger = $logger;
142
+    }
143
+
144
+    /**
145
+     * @param IProvider $provider
146
+     */
147
+    public function setTokenProvider(IProvider $provider) {
148
+        $this->tokenProvider = $provider;
149
+    }
150
+
151
+    /**
152
+     * @param string $scope
153
+     * @param string $method
154
+     * @param callable $callback
155
+     */
156
+    public function listen($scope, $method, callable $callback) {
157
+        $this->manager->listen($scope, $method, $callback);
158
+    }
159
+
160
+    /**
161
+     * @param string $scope optional
162
+     * @param string $method optional
163
+     * @param callable $callback optional
164
+     */
165
+    public function removeListener($scope = null, $method = null, callable $callback = null) {
166
+        $this->manager->removeListener($scope, $method, $callback);
167
+    }
168
+
169
+    /**
170
+     * get the manager object
171
+     *
172
+     * @return Manager|PublicEmitter
173
+     */
174
+    public function getManager() {
175
+        return $this->manager;
176
+    }
177
+
178
+    /**
179
+     * get the session object
180
+     *
181
+     * @return ISession
182
+     */
183
+    public function getSession() {
184
+        return $this->session;
185
+    }
186
+
187
+    /**
188
+     * set the session object
189
+     *
190
+     * @param ISession $session
191
+     */
192
+    public function setSession(ISession $session) {
193
+        if ($this->session instanceof ISession) {
194
+            $this->session->close();
195
+        }
196
+        $this->session = $session;
197
+        $this->activeUser = null;
198
+    }
199
+
200
+    /**
201
+     * set the currently active user
202
+     *
203
+     * @param IUser|null $user
204
+     */
205
+    public function setUser($user) {
206
+        if (is_null($user)) {
207
+            $this->session->remove('user_id');
208
+        } else {
209
+            $this->session->set('user_id', $user->getUID());
210
+        }
211
+        $this->activeUser = $user;
212
+    }
213
+
214
+    /**
215
+     * get the current active user
216
+     *
217
+     * @return IUser|null Current user, otherwise null
218
+     */
219
+    public function getUser() {
220
+        // FIXME: This is a quick'n dirty work-around for the incognito mode as
221
+        // described at https://github.com/owncloud/core/pull/12912#issuecomment-67391155
222
+        if (OC_User::isIncognitoMode()) {
223
+            return null;
224
+        }
225
+        if (is_null($this->activeUser)) {
226
+            $uid = $this->session->get('user_id');
227
+            if (is_null($uid)) {
228
+                return null;
229
+            }
230
+            $this->activeUser = $this->manager->get($uid);
231
+            if (is_null($this->activeUser)) {
232
+                return null;
233
+            }
234
+            $this->validateSession();
235
+        }
236
+        return $this->activeUser;
237
+    }
238
+
239
+    /**
240
+     * Validate whether the current session is valid
241
+     *
242
+     * - For token-authenticated clients, the token validity is checked
243
+     * - For browsers, the session token validity is checked
244
+     */
245
+    protected function validateSession() {
246
+        $token = null;
247
+        $appPassword = $this->session->get('app_password');
248
+
249
+        if (is_null($appPassword)) {
250
+            try {
251
+                $token = $this->session->getId();
252
+            } catch (SessionNotAvailableException $ex) {
253
+                return;
254
+            }
255
+        } else {
256
+            $token = $appPassword;
257
+        }
258
+
259
+        if (!$this->validateToken($token)) {
260
+            // Session was invalidated
261
+            $this->logout();
262
+        }
263
+    }
264
+
265
+    /**
266
+     * Checks whether the user is logged in
267
+     *
268
+     * @return bool if logged in
269
+     */
270
+    public function isLoggedIn() {
271
+        $user = $this->getUser();
272
+        if (is_null($user)) {
273
+            return false;
274
+        }
275
+
276
+        return $user->isEnabled();
277
+    }
278
+
279
+    /**
280
+     * set the login name
281
+     *
282
+     * @param string|null $loginName for the logged in user
283
+     */
284
+    public function setLoginName($loginName) {
285
+        if (is_null($loginName)) {
286
+            $this->session->remove('loginname');
287
+        } else {
288
+            $this->session->set('loginname', $loginName);
289
+        }
290
+    }
291
+
292
+    /**
293
+     * get the login name of the current user
294
+     *
295
+     * @return string
296
+     */
297
+    public function getLoginName() {
298
+        if ($this->activeUser) {
299
+            return $this->session->get('loginname');
300
+        }
301
+
302
+        $uid = $this->session->get('user_id');
303
+        if ($uid) {
304
+            $this->activeUser = $this->manager->get($uid);
305
+            return $this->session->get('loginname');
306
+        }
307
+
308
+        return null;
309
+    }
310
+
311
+    /**
312
+     * set the token id
313
+     *
314
+     * @param int|null $token that was used to log in
315
+     */
316
+    protected function setToken($token) {
317
+        if ($token === null) {
318
+            $this->session->remove('token-id');
319
+        } else {
320
+            $this->session->set('token-id', $token);
321
+        }
322
+    }
323
+
324
+    /**
325
+     * try to log in with the provided credentials
326
+     *
327
+     * @param string $uid
328
+     * @param string $password
329
+     * @return boolean|null
330
+     * @throws LoginException
331
+     */
332
+    public function login($uid, $password) {
333
+        $this->session->regenerateId();
334
+        if ($this->validateToken($password, $uid)) {
335
+            return $this->loginWithToken($password);
336
+        }
337
+        return $this->loginWithPassword($uid, $password);
338
+    }
339
+
340
+    /**
341
+     * @param IUser $user
342
+     * @param array $loginDetails
343
+     * @param bool $regenerateSessionId
344
+     * @return true returns true if login successful or an exception otherwise
345
+     * @throws LoginException
346
+     */
347
+    public function completeLogin(IUser $user, array $loginDetails, $regenerateSessionId = true) {
348
+        if (!$user->isEnabled()) {
349
+            // disabled users can not log in
350
+            // injecting l10n does not work - there is a circular dependency between session and \OCP\L10N\IFactory
351
+            $message = \OC::$server->getL10N('lib')->t('User disabled');
352
+            throw new LoginException($message);
353
+        }
354
+
355
+        if($regenerateSessionId) {
356
+            $this->session->regenerateId();
357
+        }
358
+
359
+        $this->setUser($user);
360
+        $this->setLoginName($loginDetails['loginName']);
361
+
362
+        if(isset($loginDetails['token']) && $loginDetails['token'] instanceof IToken) {
363
+            $this->setToken($loginDetails['token']->getId());
364
+            $this->lockdownManager->setToken($loginDetails['token']);
365
+            $firstTimeLogin = false;
366
+        } else {
367
+            $this->setToken(null);
368
+            $firstTimeLogin = $user->updateLastLoginTimestamp();
369
+        }
370
+        $this->manager->emit('\OC\User', 'postLogin', [$user, $loginDetails['password']]);
371
+        if($this->isLoggedIn()) {
372
+            $this->prepareUserLogin($firstTimeLogin, $regenerateSessionId);
373
+            return true;
374
+        }
375
+
376
+        $message = \OC::$server->getL10N('lib')->t('Login canceled by app');
377
+        throw new LoginException($message);
378
+    }
379
+
380
+    /**
381
+     * Tries to log in a client
382
+     *
383
+     * Checks token auth enforced
384
+     * Checks 2FA enabled
385
+     *
386
+     * @param string $user
387
+     * @param string $password
388
+     * @param IRequest $request
389
+     * @param OC\Security\Bruteforce\Throttler $throttler
390
+     * @throws LoginException
391
+     * @throws PasswordLoginForbiddenException
392
+     * @return boolean
393
+     */
394
+    public function logClientIn($user,
395
+                                $password,
396
+                                IRequest $request,
397
+                                OC\Security\Bruteforce\Throttler $throttler) {
398
+        $currentDelay = $throttler->sleepDelay($request->getRemoteAddress(), 'login');
399
+
400
+        if ($this->manager instanceof PublicEmitter) {
401
+            $this->manager->emit('\OC\User', 'preLogin', array($user, $password));
402
+        }
403
+
404
+        $isTokenPassword = $this->isTokenPassword($password);
405
+        if (!$isTokenPassword && $this->isTokenAuthEnforced()) {
406
+            throw new PasswordLoginForbiddenException();
407
+        }
408
+        if (!$isTokenPassword && $this->isTwoFactorEnforced($user)) {
409
+            throw new PasswordLoginForbiddenException();
410
+        }
411
+
412
+        // Try to login with this username and password
413
+        if (!$this->login($user, $password) ) {
414
+
415
+            // Failed, maybe the user used their email address
416
+            $users = $this->manager->getByEmail($user);
417
+            if (!(\count($users) === 1 && $this->login($users[0]->getUID(), $password))) {
418
+
419
+                $this->logger->warning('Login failed: \'' . $user . '\' (Remote IP: \'' . \OC::$server->getRequest()->getRemoteAddress() . '\')', ['app' => 'core']);
420
+
421
+                $throttler->registerAttempt('login', $request->getRemoteAddress(), ['uid' => $user]);
422
+                if ($currentDelay === 0) {
423
+                    $throttler->sleepDelay($request->getRemoteAddress(), 'login');
424
+                }
425
+                return false;
426
+            }
427
+        }
428
+
429
+        if ($isTokenPassword) {
430
+            $this->session->set('app_password', $password);
431
+        } else if($this->supportsCookies($request)) {
432
+            // Password login, but cookies supported -> create (browser) session token
433
+            $this->createSessionToken($request, $this->getUser()->getUID(), $user, $password);
434
+        }
435
+
436
+        return true;
437
+    }
438
+
439
+    protected function supportsCookies(IRequest $request) {
440
+        if (!is_null($request->getCookie('cookie_test'))) {
441
+            return true;
442
+        }
443
+        setcookie('cookie_test', 'test', $this->timeFactory->getTime() + 3600);
444
+        return false;
445
+    }
446
+
447
+    private function isTokenAuthEnforced() {
448
+        return $this->config->getSystemValue('token_auth_enforced', false);
449
+    }
450
+
451
+    protected function isTwoFactorEnforced($username) {
452
+        Util::emitHook(
453
+            '\OCA\Files_Sharing\API\Server2Server',
454
+            'preLoginNameUsedAsUserName',
455
+            array('uid' => &$username)
456
+        );
457
+        $user = $this->manager->get($username);
458
+        if (is_null($user)) {
459
+            $users = $this->manager->getByEmail($username);
460
+            if (empty($users)) {
461
+                return false;
462
+            }
463
+            if (count($users) !== 1) {
464
+                return true;
465
+            }
466
+            $user = $users[0];
467
+        }
468
+        // DI not possible due to cyclic dependencies :'-/
469
+        return OC::$server->getTwoFactorAuthManager()->isTwoFactorAuthenticated($user);
470
+    }
471
+
472
+    /**
473
+     * Check if the given 'password' is actually a device token
474
+     *
475
+     * @param string $password
476
+     * @return boolean
477
+     */
478
+    public function isTokenPassword($password) {
479
+        try {
480
+            $this->tokenProvider->getToken($password);
481
+            return true;
482
+        } catch (InvalidTokenException $ex) {
483
+            return false;
484
+        }
485
+    }
486
+
487
+    protected function prepareUserLogin($firstTimeLogin, $refreshCsrfToken = true) {
488
+        if ($refreshCsrfToken) {
489
+            // TODO: mock/inject/use non-static
490
+            // Refresh the token
491
+            \OC::$server->getCsrfTokenManager()->refreshToken();
492
+        }
493
+
494
+        //we need to pass the user name, which may differ from login name
495
+        $user = $this->getUser()->getUID();
496
+        OC_Util::setupFS($user);
497
+
498
+        if ($firstTimeLogin) {
499
+            // TODO: lock necessary?
500
+            //trigger creation of user home and /files folder
501
+            $userFolder = \OC::$server->getUserFolder($user);
502
+
503
+            try {
504
+                // copy skeleton
505
+                \OC_Util::copySkeleton($user, $userFolder);
506
+            } catch (NotPermittedException $ex) {
507
+                // read only uses
508
+            }
509
+
510
+            // trigger any other initialization
511
+            \OC::$server->getEventDispatcher()->dispatch(IUser::class . '::firstLogin', new GenericEvent($this->getUser()));
512
+        }
513
+    }
514
+
515
+    /**
516
+     * Tries to login the user with HTTP Basic Authentication
517
+     *
518
+     * @todo do not allow basic auth if the user is 2FA enforced
519
+     * @param IRequest $request
520
+     * @param OC\Security\Bruteforce\Throttler $throttler
521
+     * @return boolean if the login was successful
522
+     */
523
+    public function tryBasicAuthLogin(IRequest $request,
524
+                                        OC\Security\Bruteforce\Throttler $throttler) {
525
+        if (!empty($request->server['PHP_AUTH_USER']) && !empty($request->server['PHP_AUTH_PW'])) {
526
+            try {
527
+                if ($this->logClientIn($request->server['PHP_AUTH_USER'], $request->server['PHP_AUTH_PW'], $request, $throttler)) {
528
+                    /**
529
+                     * Add DAV authenticated. This should in an ideal world not be
530
+                     * necessary but the iOS App reads cookies from anywhere instead
531
+                     * only the DAV endpoint.
532
+                     * This makes sure that the cookies will be valid for the whole scope
533
+                     * @see https://github.com/owncloud/core/issues/22893
534
+                     */
535
+                    $this->session->set(
536
+                        Auth::DAV_AUTHENTICATED, $this->getUser()->getUID()
537
+                    );
538
+
539
+                    // Set the last-password-confirm session to make the sudo mode work
540
+                        $this->session->set('last-password-confirm', $this->timeFactory->getTime());
541
+
542
+                    return true;
543
+                }
544
+            } catch (PasswordLoginForbiddenException $ex) {
545
+                // Nothing to do
546
+            }
547
+        }
548
+        return false;
549
+    }
550
+
551
+    /**
552
+     * Log an user in via login name and password
553
+     *
554
+     * @param string $uid
555
+     * @param string $password
556
+     * @return boolean
557
+     * @throws LoginException if an app canceld the login process or the user is not enabled
558
+     */
559
+    private function loginWithPassword($uid, $password) {
560
+        $user = $this->manager->checkPasswordNoLogging($uid, $password);
561
+        if ($user === false) {
562
+            // Password check failed
563
+            return false;
564
+        }
565
+
566
+        return $this->completeLogin($user, ['loginName' => $uid, 'password' => $password], false);
567
+    }
568
+
569
+    /**
570
+     * Log an user in with a given token (id)
571
+     *
572
+     * @param string $token
573
+     * @return boolean
574
+     * @throws LoginException if an app canceled the login process or the user is not enabled
575
+     */
576
+    private function loginWithToken($token) {
577
+        try {
578
+            $dbToken = $this->tokenProvider->getToken($token);
579
+        } catch (InvalidTokenException $ex) {
580
+            return false;
581
+        }
582
+        $uid = $dbToken->getUID();
583
+
584
+        // When logging in with token, the password must be decrypted first before passing to login hook
585
+        $password = '';
586
+        try {
587
+            $password = $this->tokenProvider->getPassword($dbToken, $token);
588
+        } catch (PasswordlessTokenException $ex) {
589
+            // Ignore and use empty string instead
590
+        }
591
+
592
+        $this->manager->emit('\OC\User', 'preLogin', array($uid, $password));
593
+
594
+        $user = $this->manager->get($uid);
595
+        if (is_null($user)) {
596
+            // user does not exist
597
+            return false;
598
+        }
599
+
600
+        return $this->completeLogin(
601
+            $user,
602
+            [
603
+                'loginName' => $dbToken->getLoginName(),
604
+                'password' => $password,
605
+                'token' => $dbToken
606
+            ],
607
+            false);
608
+    }
609
+
610
+    /**
611
+     * Create a new session token for the given user credentials
612
+     *
613
+     * @param IRequest $request
614
+     * @param string $uid user UID
615
+     * @param string $loginName login name
616
+     * @param string $password
617
+     * @param int $remember
618
+     * @return boolean
619
+     */
620
+    public function createSessionToken(IRequest $request, $uid, $loginName, $password = null, $remember = IToken::DO_NOT_REMEMBER) {
621
+        if (is_null($this->manager->get($uid))) {
622
+            // User does not exist
623
+            return false;
624
+        }
625
+        $name = isset($request->server['HTTP_USER_AGENT']) ? $request->server['HTTP_USER_AGENT'] : 'unknown browser';
626
+        try {
627
+            $sessionId = $this->session->getId();
628
+            $pwd = $this->getPassword($password);
629
+            // Make sure the current sessionId has no leftover tokens
630
+            $this->tokenProvider->invalidateToken($sessionId);
631
+            $this->tokenProvider->generateToken($sessionId, $uid, $loginName, $pwd, $name, IToken::TEMPORARY_TOKEN, $remember);
632
+            return true;
633
+        } catch (SessionNotAvailableException $ex) {
634
+            // This can happen with OCC, where a memory session is used
635
+            // if a memory session is used, we shouldn't create a session token anyway
636
+            return false;
637
+        }
638
+    }
639
+
640
+    /**
641
+     * Checks if the given password is a token.
642
+     * If yes, the password is extracted from the token.
643
+     * If no, the same password is returned.
644
+     *
645
+     * @param string $password either the login password or a device token
646
+     * @return string|null the password or null if none was set in the token
647
+     */
648
+    private function getPassword($password) {
649
+        if (is_null($password)) {
650
+            // This is surely no token ;-)
651
+            return null;
652
+        }
653
+        try {
654
+            $token = $this->tokenProvider->getToken($password);
655
+            try {
656
+                return $this->tokenProvider->getPassword($token, $password);
657
+            } catch (PasswordlessTokenException $ex) {
658
+                return null;
659
+            }
660
+        } catch (InvalidTokenException $ex) {
661
+            return $password;
662
+        }
663
+    }
664
+
665
+    /**
666
+     * @param IToken $dbToken
667
+     * @param string $token
668
+     * @return boolean
669
+     */
670
+    private function checkTokenCredentials(IToken $dbToken, $token) {
671
+        // Check whether login credentials are still valid and the user was not disabled
672
+        // This check is performed each 5 minutes
673
+        $lastCheck = $dbToken->getLastCheck() ? : 0;
674
+        $now = $this->timeFactory->getTime();
675
+        if ($lastCheck > ($now - 60 * 5)) {
676
+            // Checked performed recently, nothing to do now
677
+            return true;
678
+        }
679
+
680
+        try {
681
+            $pwd = $this->tokenProvider->getPassword($dbToken, $token);
682
+        } catch (InvalidTokenException $ex) {
683
+            // An invalid token password was used -> log user out
684
+            return false;
685
+        } catch (PasswordlessTokenException $ex) {
686
+            // Token has no password
687
+
688
+            if (!is_null($this->activeUser) && !$this->activeUser->isEnabled()) {
689
+                $this->tokenProvider->invalidateToken($token);
690
+                return false;
691
+            }
692
+
693
+            $dbToken->setLastCheck($now);
694
+            return true;
695
+        }
696
+
697
+        // Invalidate token if the user is no longer active
698
+        if (!is_null($this->activeUser) && !$this->activeUser->isEnabled()) {
699
+            $this->tokenProvider->invalidateToken($token);
700
+            return false;
701
+        }
702
+
703
+        // If the token password is no longer valid mark it as such
704
+        if ($this->manager->checkPassword($dbToken->getLoginName(), $pwd) === false) {
705
+            $this->tokenProvider->markPasswordInvalid($dbToken, $token);
706
+            // User is logged out
707
+            return false;
708
+        }
709
+
710
+        $dbToken->setLastCheck($now);
711
+        return true;
712
+    }
713
+
714
+    /**
715
+     * Check if the given token exists and performs password/user-enabled checks
716
+     *
717
+     * Invalidates the token if checks fail
718
+     *
719
+     * @param string $token
720
+     * @param string $user login name
721
+     * @return boolean
722
+     */
723
+    private function validateToken($token, $user = null) {
724
+        try {
725
+            $dbToken = $this->tokenProvider->getToken($token);
726
+        } catch (InvalidTokenException $ex) {
727
+            return false;
728
+        }
729
+
730
+        // Check if login names match
731
+        if (!is_null($user) && $dbToken->getLoginName() !== $user) {
732
+            // TODO: this makes it imposssible to use different login names on browser and client
733
+            // e.g. login by e-mail '[email protected]' on browser for generating the token will not
734
+            //      allow to use the client token with the login name 'user'.
735
+            return false;
736
+        }
737
+
738
+        if (!$this->checkTokenCredentials($dbToken, $token)) {
739
+            return false;
740
+        }
741
+
742
+        // Update token scope
743
+        $this->lockdownManager->setToken($dbToken);
744
+
745
+        $this->tokenProvider->updateTokenActivity($dbToken);
746
+
747
+        return true;
748
+    }
749
+
750
+    /**
751
+     * Tries to login the user with auth token header
752
+     *
753
+     * @param IRequest $request
754
+     * @todo check remember me cookie
755
+     * @return boolean
756
+     */
757
+    public function tryTokenLogin(IRequest $request) {
758
+        $authHeader = $request->getHeader('Authorization');
759
+        if (strpos($authHeader, 'Bearer ') === false) {
760
+            // No auth header, let's try session id
761
+            try {
762
+                $token = $this->session->getId();
763
+            } catch (SessionNotAvailableException $ex) {
764
+                return false;
765
+            }
766
+        } else {
767
+            $token = substr($authHeader, 7);
768
+        }
769
+
770
+        if (!$this->loginWithToken($token)) {
771
+            return false;
772
+        }
773
+        if(!$this->validateToken($token)) {
774
+            return false;
775
+        }
776
+        return true;
777
+    }
778
+
779
+    /**
780
+     * perform login using the magic cookie (remember login)
781
+     *
782
+     * @param string $uid the username
783
+     * @param string $currentToken
784
+     * @param string $oldSessionId
785
+     * @return bool
786
+     */
787
+    public function loginWithCookie($uid, $currentToken, $oldSessionId) {
788
+        $this->session->regenerateId();
789
+        $this->manager->emit('\OC\User', 'preRememberedLogin', array($uid));
790
+        $user = $this->manager->get($uid);
791
+        if (is_null($user)) {
792
+            // user does not exist
793
+            return false;
794
+        }
795
+
796
+        // get stored tokens
797
+        $tokens = $this->config->getUserKeys($uid, 'login_token');
798
+        // test cookies token against stored tokens
799
+        if (!in_array($currentToken, $tokens, true)) {
800
+            return false;
801
+        }
802
+        // replace successfully used token with a new one
803
+        $this->config->deleteUserValue($uid, 'login_token', $currentToken);
804
+        $newToken = $this->random->generate(32);
805
+        $this->config->setUserValue($uid, 'login_token', $newToken, $this->timeFactory->getTime());
806
+
807
+        try {
808
+            $sessionId = $this->session->getId();
809
+            $this->tokenProvider->renewSessionToken($oldSessionId, $sessionId);
810
+        } catch (SessionNotAvailableException $ex) {
811
+            return false;
812
+        } catch (InvalidTokenException $ex) {
813
+            \OC::$server->getLogger()->warning('Renewing session token failed', ['app' => 'core']);
814
+            return false;
815
+        }
816
+
817
+        $this->setMagicInCookie($user->getUID(), $newToken);
818
+        $token = $this->tokenProvider->getToken($sessionId);
819
+
820
+        //login
821
+        $this->setUser($user);
822
+        $this->setLoginName($token->getLoginName());
823
+        $this->setToken($token->getId());
824
+        $this->lockdownManager->setToken($token);
825
+        $user->updateLastLoginTimestamp();
826
+        $password = null;
827
+        try {
828
+            $password = $this->tokenProvider->getPassword($token, $sessionId);
829
+        } catch (PasswordlessTokenException $ex) {
830
+            // Ignore
831
+        }
832
+        $this->manager->emit('\OC\User', 'postRememberedLogin', [$user, $password]);
833
+        return true;
834
+    }
835
+
836
+    /**
837
+     * @param IUser $user
838
+     */
839
+    public function createRememberMeToken(IUser $user) {
840
+        $token = $this->random->generate(32);
841
+        $this->config->setUserValue($user->getUID(), 'login_token', $token, $this->timeFactory->getTime());
842
+        $this->setMagicInCookie($user->getUID(), $token);
843
+    }
844
+
845
+    /**
846
+     * logout the user from the session
847
+     */
848
+    public function logout() {
849
+        $this->manager->emit('\OC\User', 'logout');
850
+        $user = $this->getUser();
851
+        if (!is_null($user)) {
852
+            try {
853
+                $this->tokenProvider->invalidateToken($this->session->getId());
854
+            } catch (SessionNotAvailableException $ex) {
855
+
856
+            }
857
+        }
858
+        $this->setUser(null);
859
+        $this->setLoginName(null);
860
+        $this->setToken(null);
861
+        $this->unsetMagicInCookie();
862
+        $this->session->clear();
863
+        $this->manager->emit('\OC\User', 'postLogout');
864
+    }
865
+
866
+    /**
867
+     * Set cookie value to use in next page load
868
+     *
869
+     * @param string $username username to be set
870
+     * @param string $token
871
+     */
872
+    public function setMagicInCookie($username, $token) {
873
+        $secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
874
+        $webRoot = \OC::$WEBROOT;
875
+        if ($webRoot === '') {
876
+            $webRoot = '/';
877
+        }
878
+
879
+        $maxAge = $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
880
+        \OC\Http\CookieHelper::setCookie(
881
+            'nc_username',
882
+            $username,
883
+            $maxAge,
884
+            $webRoot,
885
+            '',
886
+            $secureCookie,
887
+            true,
888
+            \OC\Http\CookieHelper::SAMESITE_LAX
889
+        );
890
+        \OC\Http\CookieHelper::setCookie(
891
+            'nc_token',
892
+            $token,
893
+            $maxAge,
894
+            $webRoot,
895
+            '',
896
+            $secureCookie,
897
+            true,
898
+            \OC\Http\CookieHelper::SAMESITE_LAX
899
+        );
900
+        try {
901
+            \OC\Http\CookieHelper::setCookie(
902
+                'nc_session_id',
903
+                $this->session->getId(),
904
+                $maxAge,
905
+                $webRoot,
906
+                '',
907
+                $secureCookie,
908
+                true,
909
+                \OC\Http\CookieHelper::SAMESITE_LAX
910
+            );
911
+        } catch (SessionNotAvailableException $ex) {
912
+            // ignore
913
+        }
914
+    }
915
+
916
+    /**
917
+     * Remove cookie for "remember username"
918
+     */
919
+    public function unsetMagicInCookie() {
920
+        //TODO: DI for cookies and IRequest
921
+        $secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
922
+
923
+        unset($_COOKIE['nc_username']); //TODO: DI
924
+        unset($_COOKIE['nc_token']);
925
+        unset($_COOKIE['nc_session_id']);
926
+        setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
927
+        setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
928
+        setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
929
+        // old cookies might be stored under /webroot/ instead of /webroot
930
+        // and Firefox doesn't like it!
931
+        setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
932
+        setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
933
+        setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
934
+    }
935
+
936
+    /**
937
+     * Update password of the browser session token if there is one
938
+     *
939
+     * @param string $password
940
+     */
941
+    public function updateSessionTokenPassword($password) {
942
+        try {
943
+            $sessionId = $this->session->getId();
944
+            $token = $this->tokenProvider->getToken($sessionId);
945
+            $this->tokenProvider->setPassword($token, $sessionId, $password);
946
+        } catch (SessionNotAvailableException $ex) {
947
+            // Nothing to do
948
+        } catch (InvalidTokenException $ex) {
949
+            // Nothing to do
950
+        }
951
+    }
952
+
953
+    public function updateTokens(string $uid, string $password) {
954
+        $this->tokenProvider->updatePasswords($uid, $password);
955
+    }
956 956
 
957 957
 
958 958
 }
Please login to merge, or discard this patch.
core/Controller/LoginController.php 1 patch
Indentation   +354 added lines, -354 removed lines patch added patch discarded remove patch
@@ -59,358 +59,358 @@
 block discarded – undo
59 59
 
60 60
 class LoginController extends Controller {
61 61
 
62
-	const LOGIN_MSG_INVALIDPASSWORD = 'invalidpassword';
63
-	const LOGIN_MSG_USERDISABLED = 'userdisabled';
64
-
65
-	/** @var IUserManager */
66
-	private $userManager;
67
-	/** @var IConfig */
68
-	private $config;
69
-	/** @var ISession */
70
-	private $session;
71
-	/** @var IUserSession|Session */
72
-	private $userSession;
73
-	/** @var IURLGenerator */
74
-	private $urlGenerator;
75
-	/** @var ILogger */
76
-	private $logger;
77
-	/** @var Manager */
78
-	private $twoFactorManager;
79
-	/** @var Defaults */
80
-	private $defaults;
81
-	/** @var Throttler */
82
-	private $throttler;
83
-
84
-	/**
85
-	 * @param string $appName
86
-	 * @param IRequest $request
87
-	 * @param IUserManager $userManager
88
-	 * @param IConfig $config
89
-	 * @param ISession $session
90
-	 * @param IUserSession $userSession
91
-	 * @param IURLGenerator $urlGenerator
92
-	 * @param ILogger $logger
93
-	 * @param Manager $twoFactorManager
94
-	 * @param Defaults $defaults
95
-	 * @param Throttler $throttler
96
-	 */
97
-	public function __construct($appName,
98
-								IRequest $request,
99
-								IUserManager $userManager,
100
-								IConfig $config,
101
-								ISession $session,
102
-								IUserSession $userSession,
103
-								IURLGenerator $urlGenerator,
104
-								ILogger $logger,
105
-								Manager $twoFactorManager,
106
-								Defaults $defaults,
107
-								Throttler $throttler) {
108
-		parent::__construct($appName, $request);
109
-		$this->userManager = $userManager;
110
-		$this->config = $config;
111
-		$this->session = $session;
112
-		$this->userSession = $userSession;
113
-		$this->urlGenerator = $urlGenerator;
114
-		$this->logger = $logger;
115
-		$this->twoFactorManager = $twoFactorManager;
116
-		$this->defaults = $defaults;
117
-		$this->throttler = $throttler;
118
-	}
119
-
120
-	/**
121
-	 * @NoAdminRequired
122
-	 * @UseSession
123
-	 *
124
-	 * @return RedirectResponse
125
-	 */
126
-	public function logout() {
127
-		$loginToken = $this->request->getCookie('nc_token');
128
-		if (!is_null($loginToken)) {
129
-			$this->config->deleteUserValue($this->userSession->getUser()->getUID(), 'login_token', $loginToken);
130
-		}
131
-		$this->userSession->logout();
132
-
133
-		$response = new RedirectResponse($this->urlGenerator->linkToRouteAbsolute('core.login.showLoginForm'));
134
-		$response->addHeader('Clear-Site-Data', '"cache", "cookies", "storage", "executionContexts"');
135
-		return $response;
136
-	}
137
-
138
-	/**
139
-	 * @PublicPage
140
-	 * @NoCSRFRequired
141
-	 * @UseSession
142
-	 *
143
-	 * @param string $user
144
-	 * @param string $redirect_url
145
-	 *
146
-	 * @return TemplateResponse|RedirectResponse
147
-	 */
148
-	public function showLoginForm(string $user = null, string $redirect_url = null): Http\Response {
149
-
150
-		if ($this->userSession->isLoggedIn()) {
151
-			return new RedirectResponse(OC_Util::getDefaultPageUrl());
152
-		}
153
-
154
-		$parameters = array();
155
-		$loginMessages = $this->session->get('loginMessages');
156
-		$errors = [];
157
-		$messages = [];
158
-		if (is_array($loginMessages)) {
159
-			list($errors, $messages) = $loginMessages;
160
-		}
161
-		$this->session->remove('loginMessages');
162
-		foreach ($errors as $value) {
163
-			$parameters[$value] = true;
164
-		}
165
-
166
-		$parameters['messages'] = $messages;
167
-		if ($user !== null && $user !== '') {
168
-			$parameters['loginName'] = $user;
169
-			$parameters['user_autofocus'] = false;
170
-		} else {
171
-			$parameters['loginName'] = '';
172
-			$parameters['user_autofocus'] = true;
173
-		}
174
-		if (!empty($redirect_url)) {
175
-			$parameters['redirect_url'] = $redirect_url;
176
-		}
177
-
178
-		$parameters = $this->setPasswordResetParameters($user, $parameters);
179
-		$parameters['alt_login'] = OC_App::getAlternativeLogIns();
180
-
181
-		if ($user !== null && $user !== '') {
182
-			$parameters['loginName'] = $user;
183
-			$parameters['user_autofocus'] = false;
184
-		} else {
185
-			$parameters['loginName'] = '';
186
-			$parameters['user_autofocus'] = true;
187
-		}
188
-
189
-		$parameters['throttle_delay'] = $this->throttler->getDelay($this->request->getRemoteAddress());
190
-
191
-		// OpenGraph Support: http://ogp.me/
192
-		Util::addHeader('meta', ['property' => 'og:title', 'content' => Util::sanitizeHTML($this->defaults->getName())]);
193
-		Util::addHeader('meta', ['property' => 'og:description', 'content' => Util::sanitizeHTML($this->defaults->getSlogan())]);
194
-		Util::addHeader('meta', ['property' => 'og:site_name', 'content' => Util::sanitizeHTML($this->defaults->getName())]);
195
-		Util::addHeader('meta', ['property' => 'og:url', 'content' => $this->urlGenerator->getAbsoluteURL('/')]);
196
-		Util::addHeader('meta', ['property' => 'og:type', 'content' => 'website']);
197
-		Util::addHeader('meta', ['property' => 'og:image', 'content' => $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core','favicon-touch.png'))]);
198
-
199
-		return new TemplateResponse(
200
-			$this->appName, 'login', $parameters, 'guest'
201
-		);
202
-	}
203
-
204
-	/**
205
-	 * Sets the password reset params.
206
-	 *
207
-	 * Users may not change their passwords if:
208
-	 * - The account is disabled
209
-	 * - The backend doesn't support password resets
210
-	 * - The password reset function is disabled
211
-	 *
212
-	 * @param string $user
213
-	 * @param array $parameters
214
-	 * @return array
215
-	 */
216
-	private function setPasswordResetParameters(
217
-		string $user = null, array $parameters): array {
218
-		if ($user !== null && $user !== '') {
219
-			$userObj = $this->userManager->get($user);
220
-		} else {
221
-			$userObj = null;
222
-		}
223
-
224
-		$parameters['resetPasswordLink'] = $this->config
225
-			->getSystemValue('lost_password_link', '');
226
-
227
-		if (!$parameters['resetPasswordLink'] && $userObj !== null) {
228
-			$parameters['canResetPassword'] = $userObj->canChangePassword();
229
-		} else if ($userObj !== null && $userObj->isEnabled() === false) {
230
-			$parameters['canResetPassword'] = false;
231
-		} else {
232
-			$parameters['canResetPassword'] = true;
233
-		}
234
-
235
-		return $parameters;
236
-	}
237
-
238
-	/**
239
-	 * @param string $redirectUrl
240
-	 * @return RedirectResponse
241
-	 */
242
-	private function generateRedirect($redirectUrl) {
243
-		if (!is_null($redirectUrl) && $this->userSession->isLoggedIn()) {
244
-			$location = $this->urlGenerator->getAbsoluteURL(urldecode($redirectUrl));
245
-			// Deny the redirect if the URL contains a @
246
-			// This prevents unvalidated redirects like ?redirect_url=:[email protected]
247
-			if (strpos($location, '@') === false) {
248
-				return new RedirectResponse($location);
249
-			}
250
-		}
251
-		return new RedirectResponse(OC_Util::getDefaultPageUrl());
252
-	}
253
-
254
-	/**
255
-	 * @PublicPage
256
-	 * @UseSession
257
-	 * @NoCSRFRequired
258
-	 * @BruteForceProtection(action=login)
259
-	 *
260
-	 * @param string $user
261
-	 * @param string $password
262
-	 * @param string $redirect_url
263
-	 * @param boolean $remember_login
264
-	 * @param string $timezone
265
-	 * @param string $timezone_offset
266
-	 * @return RedirectResponse
267
-	 */
268
-	public function tryLogin($user, $password, $redirect_url, $remember_login = true, $timezone = '', $timezone_offset = '') {
269
-		if(!is_string($user)) {
270
-			throw new \InvalidArgumentException('Username must be string');
271
-		}
272
-
273
-		// If the user is already logged in and the CSRF check does not pass then
274
-		// simply redirect the user to the correct page as required. This is the
275
-		// case when an user has already logged-in, in another tab.
276
-		if(!$this->request->passesCSRFCheck()) {
277
-			return $this->generateRedirect($redirect_url);
278
-		}
279
-
280
-		if ($this->userManager instanceof PublicEmitter) {
281
-			$this->userManager->emit('\OC\User', 'preLogin', array($user, $password));
282
-		}
283
-
284
-		$originalUser = $user;
285
-
286
-		$userObj = $this->userManager->get($user);
287
-
288
-		if ($userObj !== null && $userObj->isEnabled() === false) {
289
-			$this->logger->warning('Login failed: \''. $user . '\' disabled' .
290
-				' (Remote IP: \''. $this->request->getRemoteAddress(). '\')',
291
-				['app' => 'core']);
292
-			return $this->createLoginFailedResponse($user, $originalUser,
293
-				$redirect_url, self::LOGIN_MSG_USERDISABLED);
294
-		}
295
-
296
-		// TODO: Add all the insane error handling
297
-		/* @var $loginResult IUser */
298
-		$loginResult = $this->userManager->checkPasswordNoLogging($user, $password);
299
-		if ($loginResult === false) {
300
-			$users = $this->userManager->getByEmail($user);
301
-			// we only allow login by email if unique
302
-			if (count($users) === 1) {
303
-				$previousUser = $user;
304
-				$user = $users[0]->getUID();
305
-				if($user !== $previousUser) {
306
-					$loginResult = $this->userManager->checkPassword($user, $password);
307
-				}
308
-			}
309
-		}
310
-
311
-		if ($loginResult === false) {
312
-			$this->logger->warning('Login failed: \''. $user .
313
-				'\' (Remote IP: \''. $this->request->getRemoteAddress(). '\')',
314
-				['app' => 'core']);
315
-			return $this->createLoginFailedResponse($user, $originalUser,
316
-				$redirect_url, self::LOGIN_MSG_INVALIDPASSWORD);
317
-		}
318
-
319
-		// TODO: remove password checks from above and let the user session handle failures
320
-		// requires https://github.com/owncloud/core/pull/24616
321
-		$this->userSession->completeLogin($loginResult, ['loginName' => $user, 'password' => $password]);
322
-		$this->userSession->createSessionToken($this->request, $loginResult->getUID(), $user, $password, IToken::REMEMBER);
323
-		$this->userSession->updateTokens($loginResult->getUID(), $password);
324
-
325
-		// User has successfully logged in, now remove the password reset link, when it is available
326
-		$this->config->deleteUserValue($loginResult->getUID(), 'core', 'lostpassword');
327
-
328
-		$this->session->set('last-password-confirm', $loginResult->getLastLogin());
329
-
330
-		if ($timezone_offset !== '') {
331
-			$this->config->setUserValue($loginResult->getUID(), 'core', 'timezone', $timezone);
332
-			$this->session->set('timezone', $timezone_offset);
333
-		}
334
-
335
-		if ($this->twoFactorManager->isTwoFactorAuthenticated($loginResult)) {
336
-			$this->twoFactorManager->prepareTwoFactorLogin($loginResult, $remember_login);
337
-
338
-			$providers = $this->twoFactorManager->getProviderSet($loginResult)->getPrimaryProviders();
339
-			if (count($providers) === 1) {
340
-				// Single provider, hence we can redirect to that provider's challenge page directly
341
-				/* @var $provider IProvider */
342
-				$provider = array_pop($providers);
343
-				$url = 'core.TwoFactorChallenge.showChallenge';
344
-				$urlParams = [
345
-					'challengeProviderId' => $provider->getId(),
346
-				];
347
-			} else {
348
-				$url = 'core.TwoFactorChallenge.selectChallenge';
349
-				$urlParams = [];
350
-			}
351
-
352
-			if (!is_null($redirect_url)) {
353
-				$urlParams['redirect_url'] = $redirect_url;
354
-			}
355
-
356
-			return new RedirectResponse($this->urlGenerator->linkToRoute($url, $urlParams));
357
-		}
358
-
359
-		if ($remember_login) {
360
-			$this->userSession->createRememberMeToken($loginResult);
361
-		}
362
-
363
-		return $this->generateRedirect($redirect_url);
364
-	}
365
-
366
-	/**
367
-	 * Creates a login failed response.
368
-	 *
369
-	 * @param string $user
370
-	 * @param string $originalUser
371
-	 * @param string $redirect_url
372
-	 * @param string $loginMessage
373
-	 * @return RedirectResponse
374
-	 */
375
-	private function createLoginFailedResponse(
376
-		$user, $originalUser, $redirect_url, string $loginMessage) {
377
-		// Read current user and append if possible we need to
378
-		// return the unmodified user otherwise we will leak the login name
379
-		$args = !is_null($user) ? ['user' => $originalUser] : [];
380
-		if (!is_null($redirect_url)) {
381
-			$args['redirect_url'] = $redirect_url;
382
-		}
383
-		$response = new RedirectResponse(
384
-			$this->urlGenerator->linkToRoute('core.login.showLoginForm', $args)
385
-		);
386
-		$response->throttle(['user' => substr($user, 0, 64)]);
387
-		$this->session->set('loginMessages', [
388
-			[$loginMessage], []
389
-		]);
390
-		return $response;
391
-	}
392
-
393
-	/**
394
-	 * @NoAdminRequired
395
-	 * @UseSession
396
-	 * @BruteForceProtection(action=sudo)
397
-	 *
398
-	 * @license GNU AGPL version 3 or any later version
399
-	 *
400
-	 * @param string $password
401
-	 * @return DataResponse
402
-	 */
403
-	public function confirmPassword($password) {
404
-		$loginName = $this->userSession->getLoginName();
405
-		$loginResult = $this->userManager->checkPassword($loginName, $password);
406
-		if ($loginResult === false) {
407
-			$response = new DataResponse([], Http::STATUS_FORBIDDEN);
408
-			$response->throttle();
409
-			return $response;
410
-		}
411
-
412
-		$confirmTimestamp = time();
413
-		$this->session->set('last-password-confirm', $confirmTimestamp);
414
-		return new DataResponse(['lastLogin' => $confirmTimestamp], Http::STATUS_OK);
415
-	}
62
+    const LOGIN_MSG_INVALIDPASSWORD = 'invalidpassword';
63
+    const LOGIN_MSG_USERDISABLED = 'userdisabled';
64
+
65
+    /** @var IUserManager */
66
+    private $userManager;
67
+    /** @var IConfig */
68
+    private $config;
69
+    /** @var ISession */
70
+    private $session;
71
+    /** @var IUserSession|Session */
72
+    private $userSession;
73
+    /** @var IURLGenerator */
74
+    private $urlGenerator;
75
+    /** @var ILogger */
76
+    private $logger;
77
+    /** @var Manager */
78
+    private $twoFactorManager;
79
+    /** @var Defaults */
80
+    private $defaults;
81
+    /** @var Throttler */
82
+    private $throttler;
83
+
84
+    /**
85
+     * @param string $appName
86
+     * @param IRequest $request
87
+     * @param IUserManager $userManager
88
+     * @param IConfig $config
89
+     * @param ISession $session
90
+     * @param IUserSession $userSession
91
+     * @param IURLGenerator $urlGenerator
92
+     * @param ILogger $logger
93
+     * @param Manager $twoFactorManager
94
+     * @param Defaults $defaults
95
+     * @param Throttler $throttler
96
+     */
97
+    public function __construct($appName,
98
+                                IRequest $request,
99
+                                IUserManager $userManager,
100
+                                IConfig $config,
101
+                                ISession $session,
102
+                                IUserSession $userSession,
103
+                                IURLGenerator $urlGenerator,
104
+                                ILogger $logger,
105
+                                Manager $twoFactorManager,
106
+                                Defaults $defaults,
107
+                                Throttler $throttler) {
108
+        parent::__construct($appName, $request);
109
+        $this->userManager = $userManager;
110
+        $this->config = $config;
111
+        $this->session = $session;
112
+        $this->userSession = $userSession;
113
+        $this->urlGenerator = $urlGenerator;
114
+        $this->logger = $logger;
115
+        $this->twoFactorManager = $twoFactorManager;
116
+        $this->defaults = $defaults;
117
+        $this->throttler = $throttler;
118
+    }
119
+
120
+    /**
121
+     * @NoAdminRequired
122
+     * @UseSession
123
+     *
124
+     * @return RedirectResponse
125
+     */
126
+    public function logout() {
127
+        $loginToken = $this->request->getCookie('nc_token');
128
+        if (!is_null($loginToken)) {
129
+            $this->config->deleteUserValue($this->userSession->getUser()->getUID(), 'login_token', $loginToken);
130
+        }
131
+        $this->userSession->logout();
132
+
133
+        $response = new RedirectResponse($this->urlGenerator->linkToRouteAbsolute('core.login.showLoginForm'));
134
+        $response->addHeader('Clear-Site-Data', '"cache", "cookies", "storage", "executionContexts"');
135
+        return $response;
136
+    }
137
+
138
+    /**
139
+     * @PublicPage
140
+     * @NoCSRFRequired
141
+     * @UseSession
142
+     *
143
+     * @param string $user
144
+     * @param string $redirect_url
145
+     *
146
+     * @return TemplateResponse|RedirectResponse
147
+     */
148
+    public function showLoginForm(string $user = null, string $redirect_url = null): Http\Response {
149
+
150
+        if ($this->userSession->isLoggedIn()) {
151
+            return new RedirectResponse(OC_Util::getDefaultPageUrl());
152
+        }
153
+
154
+        $parameters = array();
155
+        $loginMessages = $this->session->get('loginMessages');
156
+        $errors = [];
157
+        $messages = [];
158
+        if (is_array($loginMessages)) {
159
+            list($errors, $messages) = $loginMessages;
160
+        }
161
+        $this->session->remove('loginMessages');
162
+        foreach ($errors as $value) {
163
+            $parameters[$value] = true;
164
+        }
165
+
166
+        $parameters['messages'] = $messages;
167
+        if ($user !== null && $user !== '') {
168
+            $parameters['loginName'] = $user;
169
+            $parameters['user_autofocus'] = false;
170
+        } else {
171
+            $parameters['loginName'] = '';
172
+            $parameters['user_autofocus'] = true;
173
+        }
174
+        if (!empty($redirect_url)) {
175
+            $parameters['redirect_url'] = $redirect_url;
176
+        }
177
+
178
+        $parameters = $this->setPasswordResetParameters($user, $parameters);
179
+        $parameters['alt_login'] = OC_App::getAlternativeLogIns();
180
+
181
+        if ($user !== null && $user !== '') {
182
+            $parameters['loginName'] = $user;
183
+            $parameters['user_autofocus'] = false;
184
+        } else {
185
+            $parameters['loginName'] = '';
186
+            $parameters['user_autofocus'] = true;
187
+        }
188
+
189
+        $parameters['throttle_delay'] = $this->throttler->getDelay($this->request->getRemoteAddress());
190
+
191
+        // OpenGraph Support: http://ogp.me/
192
+        Util::addHeader('meta', ['property' => 'og:title', 'content' => Util::sanitizeHTML($this->defaults->getName())]);
193
+        Util::addHeader('meta', ['property' => 'og:description', 'content' => Util::sanitizeHTML($this->defaults->getSlogan())]);
194
+        Util::addHeader('meta', ['property' => 'og:site_name', 'content' => Util::sanitizeHTML($this->defaults->getName())]);
195
+        Util::addHeader('meta', ['property' => 'og:url', 'content' => $this->urlGenerator->getAbsoluteURL('/')]);
196
+        Util::addHeader('meta', ['property' => 'og:type', 'content' => 'website']);
197
+        Util::addHeader('meta', ['property' => 'og:image', 'content' => $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core','favicon-touch.png'))]);
198
+
199
+        return new TemplateResponse(
200
+            $this->appName, 'login', $parameters, 'guest'
201
+        );
202
+    }
203
+
204
+    /**
205
+     * Sets the password reset params.
206
+     *
207
+     * Users may not change their passwords if:
208
+     * - The account is disabled
209
+     * - The backend doesn't support password resets
210
+     * - The password reset function is disabled
211
+     *
212
+     * @param string $user
213
+     * @param array $parameters
214
+     * @return array
215
+     */
216
+    private function setPasswordResetParameters(
217
+        string $user = null, array $parameters): array {
218
+        if ($user !== null && $user !== '') {
219
+            $userObj = $this->userManager->get($user);
220
+        } else {
221
+            $userObj = null;
222
+        }
223
+
224
+        $parameters['resetPasswordLink'] = $this->config
225
+            ->getSystemValue('lost_password_link', '');
226
+
227
+        if (!$parameters['resetPasswordLink'] && $userObj !== null) {
228
+            $parameters['canResetPassword'] = $userObj->canChangePassword();
229
+        } else if ($userObj !== null && $userObj->isEnabled() === false) {
230
+            $parameters['canResetPassword'] = false;
231
+        } else {
232
+            $parameters['canResetPassword'] = true;
233
+        }
234
+
235
+        return $parameters;
236
+    }
237
+
238
+    /**
239
+     * @param string $redirectUrl
240
+     * @return RedirectResponse
241
+     */
242
+    private function generateRedirect($redirectUrl) {
243
+        if (!is_null($redirectUrl) && $this->userSession->isLoggedIn()) {
244
+            $location = $this->urlGenerator->getAbsoluteURL(urldecode($redirectUrl));
245
+            // Deny the redirect if the URL contains a @
246
+            // This prevents unvalidated redirects like ?redirect_url=:[email protected]
247
+            if (strpos($location, '@') === false) {
248
+                return new RedirectResponse($location);
249
+            }
250
+        }
251
+        return new RedirectResponse(OC_Util::getDefaultPageUrl());
252
+    }
253
+
254
+    /**
255
+     * @PublicPage
256
+     * @UseSession
257
+     * @NoCSRFRequired
258
+     * @BruteForceProtection(action=login)
259
+     *
260
+     * @param string $user
261
+     * @param string $password
262
+     * @param string $redirect_url
263
+     * @param boolean $remember_login
264
+     * @param string $timezone
265
+     * @param string $timezone_offset
266
+     * @return RedirectResponse
267
+     */
268
+    public function tryLogin($user, $password, $redirect_url, $remember_login = true, $timezone = '', $timezone_offset = '') {
269
+        if(!is_string($user)) {
270
+            throw new \InvalidArgumentException('Username must be string');
271
+        }
272
+
273
+        // If the user is already logged in and the CSRF check does not pass then
274
+        // simply redirect the user to the correct page as required. This is the
275
+        // case when an user has already logged-in, in another tab.
276
+        if(!$this->request->passesCSRFCheck()) {
277
+            return $this->generateRedirect($redirect_url);
278
+        }
279
+
280
+        if ($this->userManager instanceof PublicEmitter) {
281
+            $this->userManager->emit('\OC\User', 'preLogin', array($user, $password));
282
+        }
283
+
284
+        $originalUser = $user;
285
+
286
+        $userObj = $this->userManager->get($user);
287
+
288
+        if ($userObj !== null && $userObj->isEnabled() === false) {
289
+            $this->logger->warning('Login failed: \''. $user . '\' disabled' .
290
+                ' (Remote IP: \''. $this->request->getRemoteAddress(). '\')',
291
+                ['app' => 'core']);
292
+            return $this->createLoginFailedResponse($user, $originalUser,
293
+                $redirect_url, self::LOGIN_MSG_USERDISABLED);
294
+        }
295
+
296
+        // TODO: Add all the insane error handling
297
+        /* @var $loginResult IUser */
298
+        $loginResult = $this->userManager->checkPasswordNoLogging($user, $password);
299
+        if ($loginResult === false) {
300
+            $users = $this->userManager->getByEmail($user);
301
+            // we only allow login by email if unique
302
+            if (count($users) === 1) {
303
+                $previousUser = $user;
304
+                $user = $users[0]->getUID();
305
+                if($user !== $previousUser) {
306
+                    $loginResult = $this->userManager->checkPassword($user, $password);
307
+                }
308
+            }
309
+        }
310
+
311
+        if ($loginResult === false) {
312
+            $this->logger->warning('Login failed: \''. $user .
313
+                '\' (Remote IP: \''. $this->request->getRemoteAddress(). '\')',
314
+                ['app' => 'core']);
315
+            return $this->createLoginFailedResponse($user, $originalUser,
316
+                $redirect_url, self::LOGIN_MSG_INVALIDPASSWORD);
317
+        }
318
+
319
+        // TODO: remove password checks from above and let the user session handle failures
320
+        // requires https://github.com/owncloud/core/pull/24616
321
+        $this->userSession->completeLogin($loginResult, ['loginName' => $user, 'password' => $password]);
322
+        $this->userSession->createSessionToken($this->request, $loginResult->getUID(), $user, $password, IToken::REMEMBER);
323
+        $this->userSession->updateTokens($loginResult->getUID(), $password);
324
+
325
+        // User has successfully logged in, now remove the password reset link, when it is available
326
+        $this->config->deleteUserValue($loginResult->getUID(), 'core', 'lostpassword');
327
+
328
+        $this->session->set('last-password-confirm', $loginResult->getLastLogin());
329
+
330
+        if ($timezone_offset !== '') {
331
+            $this->config->setUserValue($loginResult->getUID(), 'core', 'timezone', $timezone);
332
+            $this->session->set('timezone', $timezone_offset);
333
+        }
334
+
335
+        if ($this->twoFactorManager->isTwoFactorAuthenticated($loginResult)) {
336
+            $this->twoFactorManager->prepareTwoFactorLogin($loginResult, $remember_login);
337
+
338
+            $providers = $this->twoFactorManager->getProviderSet($loginResult)->getPrimaryProviders();
339
+            if (count($providers) === 1) {
340
+                // Single provider, hence we can redirect to that provider's challenge page directly
341
+                /* @var $provider IProvider */
342
+                $provider = array_pop($providers);
343
+                $url = 'core.TwoFactorChallenge.showChallenge';
344
+                $urlParams = [
345
+                    'challengeProviderId' => $provider->getId(),
346
+                ];
347
+            } else {
348
+                $url = 'core.TwoFactorChallenge.selectChallenge';
349
+                $urlParams = [];
350
+            }
351
+
352
+            if (!is_null($redirect_url)) {
353
+                $urlParams['redirect_url'] = $redirect_url;
354
+            }
355
+
356
+            return new RedirectResponse($this->urlGenerator->linkToRoute($url, $urlParams));
357
+        }
358
+
359
+        if ($remember_login) {
360
+            $this->userSession->createRememberMeToken($loginResult);
361
+        }
362
+
363
+        return $this->generateRedirect($redirect_url);
364
+    }
365
+
366
+    /**
367
+     * Creates a login failed response.
368
+     *
369
+     * @param string $user
370
+     * @param string $originalUser
371
+     * @param string $redirect_url
372
+     * @param string $loginMessage
373
+     * @return RedirectResponse
374
+     */
375
+    private function createLoginFailedResponse(
376
+        $user, $originalUser, $redirect_url, string $loginMessage) {
377
+        // Read current user and append if possible we need to
378
+        // return the unmodified user otherwise we will leak the login name
379
+        $args = !is_null($user) ? ['user' => $originalUser] : [];
380
+        if (!is_null($redirect_url)) {
381
+            $args['redirect_url'] = $redirect_url;
382
+        }
383
+        $response = new RedirectResponse(
384
+            $this->urlGenerator->linkToRoute('core.login.showLoginForm', $args)
385
+        );
386
+        $response->throttle(['user' => substr($user, 0, 64)]);
387
+        $this->session->set('loginMessages', [
388
+            [$loginMessage], []
389
+        ]);
390
+        return $response;
391
+    }
392
+
393
+    /**
394
+     * @NoAdminRequired
395
+     * @UseSession
396
+     * @BruteForceProtection(action=sudo)
397
+     *
398
+     * @license GNU AGPL version 3 or any later version
399
+     *
400
+     * @param string $password
401
+     * @return DataResponse
402
+     */
403
+    public function confirmPassword($password) {
404
+        $loginName = $this->userSession->getLoginName();
405
+        $loginResult = $this->userManager->checkPassword($loginName, $password);
406
+        if ($loginResult === false) {
407
+            $response = new DataResponse([], Http::STATUS_FORBIDDEN);
408
+            $response->throttle();
409
+            return $response;
410
+        }
411
+
412
+        $confirmTimestamp = time();
413
+        $this->session->set('last-password-confirm', $confirmTimestamp);
414
+        return new DataResponse(['lastLogin' => $confirmTimestamp], Http::STATUS_OK);
415
+    }
416 416
 }
Please login to merge, or discard this patch.
core/Migrations/Version15000Date20180926101451.php 1 patch
Indentation   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -31,23 +31,23 @@
 block discarded – undo
31 31
 
32 32
 class Version15000Date20180926101451 extends SimpleMigrationStep {
33 33
 
34
-	/**
35
-	 * @param IOutput $output
36
-	 * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
37
-	 * @param array $options
38
-	 * @return null|ISchemaWrapper
39
-	 */
40
-	public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) {
41
-		/** @var ISchemaWrapper $schema */
42
-		$schema = $schemaClosure();
34
+    /**
35
+     * @param IOutput $output
36
+     * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
37
+     * @param array $options
38
+     * @return null|ISchemaWrapper
39
+     */
40
+    public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) {
41
+        /** @var ISchemaWrapper $schema */
42
+        $schema = $schemaClosure();
43 43
 
44
-		$table = $schema->getTable('authtoken');
45
-		$table->addColumn('password_invalid','boolean', [
46
-			'notnull' => true,
47
-			'default' => false,
48
-		]);
44
+        $table = $schema->getTable('authtoken');
45
+        $table->addColumn('password_invalid','boolean', [
46
+            'notnull' => true,
47
+            'default' => false,
48
+        ]);
49 49
 
50
-		return $schema;
51
-	}
50
+        return $schema;
51
+    }
52 52
 
53 53
 }
Please login to merge, or discard this patch.