Skip to content

Commit 817f1f6

Browse files
author
Greg Bowler
committed
Update provider uri and cipher to allow user session to be maintained on provider
1 parent cec4846 commit 817f1f6

File tree

8 files changed

+103
-53
lines changed

8 files changed

+103
-53
lines changed

src/Authenticator.php

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
use Authwave\ProviderUri\AbstractProviderUri;
55
use Authwave\ProviderUri\AdminUri;
6-
use Authwave\ProviderUri\AuthUri;
6+
use Authwave\ProviderUri\LoginUri;
77
use Authwave\ProviderUri\ProfileUri;
88
use Gt\Http\Uri;
99
use Gt\Session\SessionContainer;
@@ -76,15 +76,18 @@ public function login(Token $token = null):void {
7676
$this->sessionData = new SessionData($token);
7777
$this->session->set(self::SESSION_KEY, $this->sessionData);
7878

79-
$this->redirectHandler->redirect($this->getAuthUri($token));
79+
$this->redirectHandler->redirect($this->getLoginUri($token));
8080
}
8181

82-
public function logout(string $redirectToPath = "/"):void {
83-
$this->session->remove(self::SESSION_KEY);
82+
public function logout(Token $token = null):void {
83+
if(is_null($token)) {
84+
$token = new Token($this->clientKey);
85+
}
86+
87+
$this->sessionData = new SessionData($token);
88+
$this->session->set(self::SESSION_KEY, $this->sessionData);
8489

85-
$uri = (new Uri())
86-
->withPath($redirectToPath);
87-
$this->redirectHandler->redirect($uri);
90+
$this->redirectHandler->redirect($this->getLogoutUri($token));
8891
}
8992

9093
public function getUuid():string {
@@ -102,8 +105,16 @@ public function getField(string $name):?string {
102105
return $userData->getField($name);
103106
}
104107

105-
public function getAuthUri(Token $token):AbstractProviderUri {
106-
return new AuthUri(
108+
public function getLoginUri(Token $token):AbstractProviderUri {
109+
return new LoginUri(
110+
$token,
111+
$this->currentUriPath,
112+
$this->authwaveHost
113+
);
114+
}
115+
116+
private function getLogoutUri(Token $token):AbstractProviderUri {
117+
return new LogoutUri(
107118
$token,
108119
$this->currentUriPath,
109120
$this->authwaveHost
@@ -114,8 +125,17 @@ public function getAdminUri():UriInterface {
114125
return new AdminUri($this->authwaveHost);
115126
}
116127

117-
public function getProfileUri():UriInterface {
118-
return new ProfileUri($this->authwaveHost);
128+
public function getProfileUri(Token $token = null):UriInterface {
129+
if(is_null($token)) {
130+
$token = new Token($this->clientKey);
131+
}
132+
133+
return new ProfileUri(
134+
$token,
135+
$this->getUuid(),
136+
$this->currentUriPath,
137+
$this->authwaveHost
138+
);
119139
}
120140

121141
private function completeAuth():void {
@@ -132,6 +152,8 @@ private function completeAuth():void {
132152
new SessionData($token, $userData)
133153
);
134154

155+
setcookie("authwave-trackshift", "test", 0, "/", "localhost");
156+
135157
$this->redirectHandler->redirect(
136158
(new Uri($this->currentUriPath))
137159
->withoutQueryValue(self::RESPONSE_QUERY_PARAMETER)

src/ProviderUri/AbstractProviderUri.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22
namespace Authwave\ProviderUri;
33

44
use Authwave\InsecureProtocolException;
5+
use Authwave\Token;
56
use Gt\Http\Uri;
67

78
abstract class AbstractProviderUri extends Uri {
89
const DEFAULT_BASE_REMOTE_URI = "login.authwave.com";
10+
const QUERY_STRING_CIPHER = "c";
11+
const QUERY_STRING_INIT_VECTOR = "i";
12+
const QUERY_STRING_CURRENT_PATH = "p";
913

1014
protected function normaliseBaseUri(string $baseUri):Uri {
1115
$scheme = parse_url($baseUri, PHP_URL_SCHEME)
@@ -27,4 +31,16 @@ protected function normaliseBaseUri(string $baseUri):Uri {
2731

2832
return $uri;
2933
}
34+
35+
protected function buildQuery(
36+
Token $token,
37+
string $currentPath,
38+
string $data = null
39+
):string {
40+
return http_build_query([
41+
self::QUERY_STRING_CIPHER => (string)$token->generateRequestCipher($data),
42+
self::QUERY_STRING_INIT_VECTOR => (string)$token->getIv(),
43+
self::QUERY_STRING_CURRENT_PATH => bin2hex($currentPath),
44+
]);
45+
}
3046
}

src/ProviderUri/AuthUri.php renamed to src/ProviderUri/LoginUri.php

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
use Authwave\Token;
55
use Gt\Http\Uri;
66

7-
class AuthUri extends AbstractProviderUri {
8-
const QUERY_STRING_CIPHER = "cipher";
9-
const QUERY_STRING_INIT_VECTOR = "iv";
10-
const QUERY_STRING_CURRENT_PATH = "path";
11-
7+
/**
8+
* The AuthUri class represents the Uri used to redirect the user agent to the
9+
* Authwave provider in order to initiate authentication. A Token is used to
10+
* pass the secret IV to the provider, encrypted with the API key. The secret
11+
* IV is only ever stored in the client's session, and is unique to the session.
12+
*/
13+
class LoginUri extends AbstractProviderUri {
1214
/**
1315
* @param Token $token This must be the same instance of the Token when
1416
* creating Authenticator for the first time as it is when checking the
@@ -25,11 +27,6 @@ public function __construct(
2527
) {
2628
$baseRemoteUri = $this->normaliseBaseUri($baseRemoteUri);
2729
parent::__construct($baseRemoteUri);
28-
29-
$this->query = http_build_query([
30-
self::QUERY_STRING_CIPHER => (string)$token->generateRequestCipher(),
31-
self::QUERY_STRING_INIT_VECTOR => (string)$token->getIv(),
32-
self::QUERY_STRING_CURRENT_PATH => $currentPath,
33-
]);
30+
$this->query = $this->buildQuery($token, $currentPath);
3431
}
3532
}

src/ProviderUri/ProfileUri.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
<?php
22
namespace Authwave\ProviderUri;
33

4+
use Authwave\Token;
5+
46
class ProfileUri extends AbstractProviderUri {
57
public function __construct(
8+
Token $token,
9+
string $uuid,
10+
string $currentPath,
611
string $baseRemoteUri
712
) {
813
$baseRemoteUri = $this->normaliseBaseUri($baseRemoteUri);
914
parent::__construct($baseRemoteUri);
1015
$this->path = "/profile";
16+
$this->query = $this->buildQuery($token, $uuid);
1117
}
1218
}

src/Token.php

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,22 @@ public function getIv():InitVector {
2424
return $this->iv;
2525
}
2626

27-
// The request cipher is sent to the remote provider in the querystring. It
28-
// consists of the secret IV, encrypted with the client key. The remote provider
29-
// will decrypt the secret and use it as the key when encrypting the response
30-
// cipher, which will be sent back to the client application in the querystring.
31-
public function generateRequestCipher():string {
27+
/**
28+
* The request cipher is sent to the remote provider in the querystring. It
29+
* consists of the token's secret IV, encrypted with the client key, along with
30+
* an optional message. The secret IV is required for two-way encryption. The
31+
* remote provider will decrypt the secret and use it as the key if encrypting a
32+
* response cipher, which will be sent back to the client application in the
33+
* querystring.
34+
*/
35+
public function generateRequestCipher(string $message = null):string {
36+
$data = $this->secretIv;
37+
if($message) {
38+
$data .= "|" . $message;
39+
}
40+
3241
$rawCipher = openssl_encrypt(
33-
$this->secretIv,
42+
$data,
3443
self::ENCRYPTION_METHOD,
3544
$this->key,
3645
0,

test/phpunit/AuthenticatorTest.php

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use Authwave\InitVector;
66
use Authwave\NotLoggedInException;
77
use Authwave\ProviderUri\AdminUri;
8-
use Authwave\ProviderUri\AuthUri;
8+
use Authwave\ProviderUri\LoginUri;
99
use Authwave\ProviderUri\LogoutUri;
1010
use Authwave\RedirectHandler;
1111
use Authwave\SessionData;
@@ -74,7 +74,7 @@ public function testLogoutClearsSession() {
7474
$sut = new Authenticator(
7575
"test-key",
7676
"/",
77-
AuthUri::DEFAULT_BASE_REMOTE_URI,
77+
LoginUri::DEFAULT_BASE_REMOTE_URI,
7878
null,
7979
$redirectHandler
8080
);
@@ -89,13 +89,13 @@ public function testLoginRedirects() {
8989
$redirectHandler->expects(self::once())
9090
->method("redirect")
9191
->with(self::callback(fn(UriInterface $uri) =>
92-
$uri->getHost() === AuthUri::DEFAULT_BASE_REMOTE_URI
92+
$uri->getHost() === LoginUri::DEFAULT_BASE_REMOTE_URI
9393
));
9494

9595
$sut = new Authenticator(
9696
"test-key",
9797
"/",
98-
AuthUri::DEFAULT_BASE_REMOTE_URI,
98+
LoginUri::DEFAULT_BASE_REMOTE_URI,
9999
null,
100100
$redirectHandler
101101
);
@@ -144,9 +144,9 @@ public function testLoginRedirectsWithCorrectQueryString() {
144144
->willReturn($iv);
145145

146146
$expectedQueryParts = [
147-
AuthUri::QUERY_STRING_CIPHER => $cipher,
148-
AuthUri::QUERY_STRING_INIT_VECTOR => $ivString,
149-
AuthUri::QUERY_STRING_CURRENT_PATH => $currentPath,
147+
LoginUri::QUERY_STRING_CIPHER => $cipher,
148+
LoginUri::QUERY_STRING_INIT_VECTOR => $ivString,
149+
LoginUri::QUERY_STRING_CURRENT_PATH => $currentPath,
150150
];
151151
$expectedQuery = http_build_query($expectedQueryParts);
152152

@@ -160,7 +160,7 @@ public function testLoginRedirectsWithCorrectQueryString() {
160160
$sut = new Authenticator(
161161
$key,
162162
$currentPath,
163-
AuthUri::DEFAULT_BASE_REMOTE_URI,
163+
LoginUri::DEFAULT_BASE_REMOTE_URI,
164164
null,
165165
$redirectHandler
166166
);
@@ -180,7 +180,7 @@ public function testLoginDoesNothingWhenAlreadyLoggedIn() {
180180
$sut = new Authenticator(
181181
"test-key",
182182
"/",
183-
AuthUri::DEFAULT_BASE_REMOTE_URI,
183+
LoginUri::DEFAULT_BASE_REMOTE_URI,
184184
null,
185185
$redirectHandler
186186
);
@@ -290,7 +290,7 @@ public function testCompleteAuth() {
290290
new Authenticator(
291291
"test-key",
292292
$currentUri,
293-
AuthUri::DEFAULT_BASE_REMOTE_URI,
293+
LoginUri::DEFAULT_BASE_REMOTE_URI,
294294
null,
295295
$redirectHandler
296296
);
@@ -317,7 +317,7 @@ public function testCompleteAuthNotAffectedByQueryString() {
317317
new Authenticator(
318318
"test-key",
319319
"/example-path?filter=something",
320-
AuthUri::DEFAULT_BASE_REMOTE_URI,
320+
LoginUri::DEFAULT_BASE_REMOTE_URI,
321321
null,
322322
$redirectHandler
323323
);
@@ -328,7 +328,7 @@ public function testGetAdminUri() {
328328
$auth = new Authenticator(
329329
"test-key",
330330
"/example-path",
331-
AuthUri::DEFAULT_BASE_REMOTE_URI
331+
LoginUri::DEFAULT_BASE_REMOTE_URI
332332
);
333333
$sut = $auth->getAdminUri();
334334
self::assertEquals(

test/phpunit/ProviderUri/AbstractProviderUriTest.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
use Authwave\InitVector;
55
use Authwave\InsecureProtocolException;
6-
use Authwave\ProviderUri\AuthUri;
6+
use Authwave\ProviderUri\LoginUri;
77
use Authwave\Token;
88
use PHPUnit\Framework\TestCase;
99
use Psr\Http\Message\UriInterface;
@@ -15,7 +15,7 @@ public function testAuthUriHttps() {
1515
->willReturn("https://example.com");
1616
$token = self::createMock(Token::class);
1717

18-
$sut = new AuthUri(
18+
$sut = new LoginUri(
1919
$token,
2020
"",
2121
$baseUri
@@ -35,7 +35,7 @@ public function testAuthUriWithNonStandardPort() {
3535
->willReturn("http://localhost:8081");
3636
$token = self::createMock(Token::class);
3737

38-
$sut = new AuthUri(
38+
$sut = new LoginUri(
3939
$token,
4040
"",
4141
$baseUri
@@ -54,7 +54,7 @@ public function testAuthUriWithNonStandardPort() {
5454
// But it should still default to HTTPS on localhost.
5555
public function testGetAuthUriHostnameLocalhostHttpsByDefault() {
5656
$token = self::createMock(Token::class);
57-
$sut = new AuthUri(
57+
$sut = new LoginUri(
5858
$token,
5959
"/",
6060
"localhost"
@@ -69,7 +69,7 @@ public function testGetAuthUriHostnameLocalhostHttpsByDefault() {
6969
// We should be able to set the scheme to HTTP for localhost hostname only.
7070
public function testGetAuthUriHostnameLocalhostHttpAllowed() {
7171
$token = self::createMock(Token::class);
72-
$sut = new AuthUri(
72+
$sut = new LoginUri(
7373
$token,
7474
"/",
7575
"http://localhost"
@@ -84,7 +84,7 @@ public function testGetAuthUriHostnameLocalhostHttpAllowed() {
8484
public function testGetAuthUriHostnameNotLocalhostHttpNotAllowed() {
8585
$token = self::createMock(Token::class);
8686
self::expectException(InsecureProtocolException::class);
87-
new AuthUri(
87+
new LoginUri(
8888
$token,
8989
"/",
9090
"http://localhost.com"
@@ -98,7 +98,7 @@ public function testAuthUriHttpsInferred() {
9898
// Note on the line above, no scheme is passed in - we must assume https.
9999
$token = self::createMock(Token::class);
100100

101-
$sut = new AuthUri(
101+
$sut = new LoginUri(
102102
$token,
103103
"/",
104104
$baseUri);

test/phpunit/ProviderUri/AuthUriTest.php renamed to test/phpunit/ProviderUri/LoginUriTest.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
namespace Authwave\Test\ProviderUri;
33

44
use Authwave\InitVector;
5-
use Authwave\ProviderUri\AuthUri;
5+
use Authwave\ProviderUri\LoginUri;
66
use Authwave\Token;
77
use PHPUnit\Framework\TestCase;
88
use Psr\Http\Message\UriInterface;
99

10-
class AuthUriTest extends TestCase {
10+
class LoginUriTest extends TestCase {
1111
public function testQueryString() {
1212
$mockCipherValue = str_repeat("f", 16);
1313
$mockIvValue = str_repeat("0", 16);
@@ -23,7 +23,7 @@ public function testQueryString() {
2323
->willReturn($iv);
2424

2525
$returnPath = "/examplePage";
26-
$sut = new AuthUri(
26+
$sut = new LoginUri(
2727
$token,
2828
$returnPath,
2929
$baseUri
@@ -32,17 +32,17 @@ public function testQueryString() {
3232

3333
self::assertEquals(
3434
$mockCipherValue,
35-
$queryParts[AuthUri::QUERY_STRING_CIPHER],
35+
$queryParts[LoginUri::QUERY_STRING_CIPHER],
3636
);
3737

3838
self::assertEquals(
3939
$mockIvValue,
40-
$queryParts[AuthUri::QUERY_STRING_INIT_VECTOR]
40+
$queryParts[LoginUri::QUERY_STRING_INIT_VECTOR]
4141
);
4242

4343
self::assertEquals(
4444
$returnPath,
45-
$queryParts[AuthUri::QUERY_STRING_CURRENT_PATH]
45+
$queryParts[LoginUri::QUERY_STRING_CURRENT_PATH]
4646
);
4747
}
4848
}

0 commit comments

Comments
 (0)