Skip to content

Commit cf05011

Browse files
solevicsolevic
authored andcommitted
Add Device Authorization Grant tests
1 parent a737482 commit cf05011

10 files changed

Lines changed: 873 additions & 3 deletions

library/javatests/net/openid/appauth/AuthStateTest.java

Lines changed: 187 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,28 @@
2020
import static net.openid.appauth.TestValues.TEST_ID_TOKEN;
2121
import static net.openid.appauth.TestValues.TEST_REFRESH_TOKEN;
2222
import static net.openid.appauth.TestValues.getMinimalAuthRequestBuilder;
23+
import static net.openid.appauth.TestValues.getMinimalDeviceAuthRequestBuilder;
2324
import static net.openid.appauth.TestValues.getTestAuthCodeExchangeResponse;
2425
import static net.openid.appauth.TestValues.getTestAuthCodeExchangeResponseBuilder;
2526
import static net.openid.appauth.TestValues.getTestAuthRequest;
2627
import static net.openid.appauth.TestValues.getTestAuthResponse;
2728
import static net.openid.appauth.TestValues.getTestAuthResponseBuilder;
29+
import static net.openid.appauth.TestValues.getTestDeviceAuthorizationResponse;
2830
import static net.openid.appauth.TestValues.getTestRegistrationResponse;
2931
import static net.openid.appauth.TestValues.getTestRegistrationResponseBuilder;
3032
import static org.assertj.core.api.Assertions.assertThat;
33+
import static org.junit.Assert.assertTrue;
3134
import static org.mockito.ArgumentMatchers.any;
35+
import static org.mockito.ArgumentMatchers.anyLong;
3236
import static org.mockito.ArgumentMatchers.eq;
37+
import static org.mockito.ArgumentMatchers.isNull;
3338
import static org.mockito.Mockito.mock;
3439
import static org.mockito.Mockito.times;
3540
import static org.mockito.Mockito.verify;
3641
import static org.mockito.Mockito.verifyNoInteractions;
42+
import static org.mockito.Mockito.when;
43+
44+
import androidx.annotation.Nullable;
3745

3846
import java.util.Collections;
3947
import org.junit.Before;
@@ -71,6 +79,7 @@ public void testInitialState() {
7179
assertThat(state.getLastAuthorizationResponse()).isNull();
7280
assertThat(state.getLastTokenResponse()).isNull();
7381
assertThat(state.getLastRegistrationResponse()).isNull();
82+
assertThat(state.getLastDeviceAuthorizationResponse()).isNull();
7483

7584
assertThat(state.getScope()).isNull();
7685
assertThat(state.getScopeSet()).isNull();
@@ -93,6 +102,7 @@ public void testInitialState_fromAuthorizationResponse() {
93102
assertThat(state.getAuthorizationException()).isNull();
94103
assertThat(state.getLastAuthorizationResponse()).isSameAs(resp);
95104
assertThat(state.getLastTokenResponse()).isNull();
105+
assertThat(state.getLastDeviceAuthorizationResponse()).isNull();
96106

97107
assertThat(state.getScope()).isEqualTo(authCodeRequest.scope);
98108
assertThat(state.getScopeSet()).isEqualTo(authCodeRequest.getScopeSet());
@@ -103,7 +113,7 @@ public void testInitialState_fromAuthorizationResponse() {
103113
@Test
104114
public void testInitialState_fromAuthorizationException() {
105115
AuthState state = new AuthState(
106-
null,
116+
(AuthorizationResponse) null,
107117
AuthorizationException.AuthorizationRequestErrors.ACCESS_DENIED);
108118

109119
assertThat(state.isAuthorized()).isFalse();
@@ -181,6 +191,28 @@ public void testInitialState_fromRegistrationResponse() {
181191
assertThat(state.getNeedsTokenRefresh(mClock)).isTrue();
182192
}
183193

194+
@Test
195+
public void testInitialState_fromDeviceAuthResponse() {
196+
DeviceAuthorizationResponse deviceAuthResp = getTestDeviceAuthorizationResponse();
197+
AuthState state = new AuthState(deviceAuthResp, null);
198+
199+
assertThat(state.isAuthorized()).isFalse();
200+
assertThat(state.getAccessToken()).isNull();
201+
assertThat(state.getAccessTokenExpirationTime()).isNull();
202+
assertThat(state.getIdToken()).isNull();
203+
assertThat(state.getRefreshToken()).isNull();
204+
205+
assertThat(state.getAuthorizationException()).isNull();
206+
assertThat(state.getLastAuthorizationResponse()).isNull();
207+
assertThat(state.getLastTokenResponse()).isNull();
208+
assertThat(state.getLastRegistrationResponse()).isNull();
209+
assertThat(state.getLastDeviceAuthorizationResponse()).isSameAs(deviceAuthResp);
210+
211+
assertThat(state.getScope()).isNull();
212+
assertThat(state.getScopeSet()).isNull();
213+
assertThat(state.getNeedsTokenRefresh(mClock)).isTrue();
214+
}
215+
184216
@Test(expected = IllegalArgumentException.class)
185217
public void testConstructor_withAuthResponseAndException() {
186218
new AuthState(getTestAuthResponse(),
@@ -225,6 +257,25 @@ public void testUpdate_tokenResponseWithException_ignoredErrorType() {
225257
assertThat(state.getAuthorizationException()).isNull();
226258
}
227259

260+
@Test
261+
public void testUpdate_deviceAuthResponseWithException_deviceAuthErrorType() {
262+
AuthState state = new AuthState();
263+
state.update((DeviceAuthorizationResponse) null,
264+
AuthorizationException.DeviceCodeRequestErrors.ACCESS_DENIED);
265+
266+
assertThat(state.getAuthorizationException())
267+
.isSameAs(AuthorizationException.DeviceCodeRequestErrors.ACCESS_DENIED);
268+
}
269+
270+
@Test
271+
public void testUpdate_deviceAuthResponseWithException_ignoredErrorType() {
272+
AuthState state = new AuthState();
273+
state.update((DeviceAuthorizationResponse) null,
274+
AuthorizationException.GeneralErrors.SERVER_ERROR);
275+
276+
assertThat(state.getAuthorizationException()).isNull();
277+
}
278+
228279
@Test(expected = IllegalArgumentException.class)
229280
public void testUpdate_withAuthResponseAndException() {
230281
AuthState state = new AuthState();
@@ -239,6 +290,13 @@ public void testUpdate_withTokenResponseAndException() {
239290
AuthorizationException.AuthorizationRequestErrors.ACCESS_DENIED);
240291
}
241292

293+
@Test(expected = IllegalArgumentException.class)
294+
public void testUpdate_withDeviceAuthResponseAndException() {
295+
AuthState state = new AuthState();
296+
state.update(getTestDeviceAuthorizationResponse(),
297+
AuthorizationException.AuthorizationRequestErrors.ACCESS_DENIED);
298+
}
299+
242300
@Test
243301
public void testGetAccessToken_fromAuthResponse() {
244302
AuthorizationRequest authReq = getMinimalAuthRequestBuilder("code token")
@@ -319,6 +377,60 @@ public void testGetIdToken_fromTokenResponse() {
319377
assertThat(state.getIdToken()).isEqualTo(tokenResp.idToken);
320378
}
321379

380+
@Test
381+
public void testGetConfiguration() {
382+
AuthorizationResponse authResp = getTestAuthResponse();
383+
AuthState state = new AuthState(authResp, null);
384+
assertThat(state.getConfiguration()).isEqualTo(authResp.request.configuration);
385+
386+
TokenResponse tokenResp = getTestAuthCodeExchangeResponse();
387+
state.update(tokenResp, null);
388+
assertThat(state.getConfiguration()).isEqualTo(tokenResp.request.configuration);
389+
390+
DeviceAuthorizationResponse deviceAuthResp = getTestDeviceAuthorizationResponse();
391+
state.update(deviceAuthResp, null);
392+
assertThat(state.getConfiguration()).isEqualTo(deviceAuthResp.request.configuration);
393+
}
394+
395+
@Test
396+
public void testGetClientId_fromAuthResponse() {
397+
AuthorizationResponse authResp = getTestAuthResponse();
398+
AuthState state = new AuthState(authResp, null);
399+
400+
assertThat(state.getClientId()).isEqualTo((Object) authResp.request.clientId);
401+
}
402+
403+
@Test
404+
public void testGetClientId_fromTokenResponse() {
405+
AuthorizationRequest authReq = getMinimalAuthRequestBuilder("code")
406+
.setClientId("123456")
407+
.build();
408+
AuthorizationResponse authResp = new AuthorizationResponse.Builder(authReq)
409+
.build();
410+
TokenResponse tokenResp = getTestAuthCodeExchangeResponse();
411+
AuthState state = new AuthState(authResp, tokenResp, null);
412+
413+
// in this scenario, we have a client ID on both the authorization response and the
414+
// token response. The value on the token response takes precedence.
415+
assertThat(state.getClientId()).isEqualTo((Object) tokenResp.request.clientId);
416+
}
417+
418+
@Test
419+
public void testGetClientId_fromDeviceAuthResponse() {
420+
AuthorizationRequest authReq = getMinimalAuthRequestBuilder("code")
421+
.setClientId("123456")
422+
.build();
423+
AuthorizationResponse authResp = new AuthorizationResponse.Builder(authReq)
424+
.build();
425+
DeviceAuthorizationResponse deviceAuthResp = getTestDeviceAuthorizationResponse();
426+
AuthState state = new AuthState(authResp,null);
427+
state.update(deviceAuthResp, null);
428+
429+
// in this scenario, we have a client ID on both the authorization response and the device
430+
// authorization response. The value on the device authorization response takes precedence.
431+
assertThat(state.getClientId()).isEqualTo((Object) deviceAuthResp.request.clientId);
432+
}
433+
322434
@Test
323435
public void testCreateTokenRefreshRequest() {
324436
AuthorizationResponse authResp = getTestAuthResponse();
@@ -580,6 +692,70 @@ public void testPerformActionWithFreshToken_afterTokenExpiration_multipleActions
580692
assertThat(state.getIdToken()).isEqualTo(freshIdToken);
581693
}
582694

695+
@Test
696+
public void testPerformTokenPollRequest() {
697+
DeviceAuthorizationResponse deviceAuthResp = getTestDeviceAuthorizationResponse();
698+
AuthState state = new AuthState(deviceAuthResp, null);
699+
700+
AuthorizationService service = mock(AuthorizationService.class);
701+
AuthorizationService.TokenResponseCallback callback =
702+
mock(AuthorizationService.TokenResponseCallback.class);
703+
704+
state.performTokenPollRequest(service, callback);
705+
706+
verify(service, times(1)).performTokenPollRequest(
707+
any(TokenRequest.class),
708+
any(ClientAuthentication.class),
709+
anyLong(),
710+
anyLong(),
711+
any(AuthorizationService.TokenResponseCallback.class));
712+
}
713+
714+
@Test
715+
public void testPerformTokenPollRequest_deviceAuthMissingError() {
716+
AuthState state = new AuthState();
717+
718+
AuthorizationService service = mock(AuthorizationService.class);
719+
AuthorizationService.TokenResponseCallback callback =
720+
mock(AuthorizationService.TokenResponseCallback.class);
721+
722+
state.performTokenPollRequest(service, callback);
723+
724+
ArgumentCaptor<AuthorizationException> exceptionCaptor =
725+
ArgumentCaptor.forClass(AuthorizationException.class);
726+
727+
verify(callback, times(1)).onTokenRequestCompleted(
728+
ArgumentMatchers.<TokenResponse>isNull(),
729+
exceptionCaptor.capture());
730+
731+
assertThat(exceptionCaptor.getValue())
732+
.isEqualTo(AuthorizationException.DeviceCodeRequestErrors.CLIENT_ERROR);
733+
}
734+
735+
@Test
736+
public void testCancelTokenPoll() {
737+
DeviceAuthorizationResponse deviceAuthResp = getTestDeviceAuthorizationResponse();
738+
AuthState state = new AuthState(deviceAuthResp, null);
739+
740+
AuthorizationService service = mock(AuthorizationService.class);
741+
AuthorizationService.TokenResponseCallback callback =
742+
mock(AuthorizationService.TokenResponseCallback.class);
743+
CancelAsyncTaskRunnable cancelRunnable = mock(CancelAsyncTaskRunnable.class);
744+
745+
when(service.performTokenPollRequest(
746+
any(TokenRequest.class),
747+
any(ClientAuthentication.class),
748+
anyLong(),
749+
anyLong(),
750+
any(AuthorizationService.TokenResponseCallback.class)
751+
)).thenReturn(cancelRunnable);
752+
753+
state.performTokenPollRequest(service, callback);
754+
state.cancelTokenPoll();
755+
756+
verify(cancelRunnable, times(1)).run();
757+
}
758+
583759
@Test
584760
public void testJsonSerialization() throws Exception {
585761
AuthorizationRequest authReq = getMinimalAuthRequestBuilder("id_token token code")
@@ -597,8 +773,10 @@ public void testJsonSerialization() throws Exception {
597773

598774
TokenResponse tokenResp = getTestAuthCodeExchangeResponse();
599775
RegistrationResponse regResp = getTestRegistrationResponse();
776+
DeviceAuthorizationResponse deviceAuthResp = getTestDeviceAuthorizationResponse();
600777
AuthState state = new AuthState(authResp, tokenResp, null);
601778
state.update(regResp);
779+
state.update(deviceAuthResp, null);
602780

603781
String json = state.jsonSerializeString();
604782
AuthState restoredState = AuthState.jsonDeserialize(json);
@@ -610,6 +788,11 @@ public void testJsonSerialization() throws Exception {
610788
.isEqualTo(state.getAccessTokenExpirationTime());
611789
assertThat(restoredState.getIdToken()).isEqualTo(state.getIdToken());
612790
assertThat(restoredState.getRefreshToken()).isEqualTo(state.getRefreshToken());
791+
assertThat(restoredState.getUserCode()).isEqualTo(state.getUserCode());
792+
assertThat(restoredState.getCodeExpirationTime()).isEqualTo(state.getCodeExpirationTime());
793+
assertThat(restoredState.getVerificationUri()).isEqualTo(state.getVerificationUri());
794+
assertThat(restoredState.getVerificationUriComplete())
795+
.isEqualTo(state.getVerificationUriComplete());
613796
assertThat(restoredState.getScope()).isEqualTo(state.getScope());
614797
assertThat(restoredState.getNeedsTokenRefresh(mClock))
615798
.isEqualTo(state.getNeedsTokenRefresh(mClock));
@@ -635,8 +818,10 @@ public void testJsonSerialization_doesNotChange() throws Exception {
635818

636819
TokenResponse tokenResp = getTestAuthCodeExchangeResponse();
637820
RegistrationResponse regResp = getTestRegistrationResponse();
821+
DeviceAuthorizationResponse deviceAuthResp = getTestDeviceAuthorizationResponse();
638822
AuthState state = new AuthState(authResp, tokenResp, null);
639823
state.update(regResp);
824+
state.update(deviceAuthResp, null);
640825

641826
String firstOutput = state.jsonSerializeString();
642827
String secondOutput = AuthState.jsonDeserialize(firstOutput).jsonSerializeString();
@@ -647,7 +832,7 @@ public void testJsonSerialization_doesNotChange() throws Exception {
647832
@Test
648833
public void testJsonSerialization_withException() throws Exception {
649834
AuthState state = new AuthState(
650-
null,
835+
(AuthorizationResponse) null,
651836
AuthorizationException.AuthorizationRequestErrors.INVALID_REQUEST);
652837

653838
AuthState restored = AuthState.jsonDeserialize(state.jsonSerializeString());

library/javatests/net/openid/appauth/AuthorizationServiceConfigurationTest.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ public class AuthorizationServiceConfigurationTest {
6060
private static final String TEST_TOKEN_ENDPOINT = "https://test.openid.com/o/oauth/token";
6161
private static final String TEST_END_SESSION_ENDPOINT = "https://test.openid.com/o/oauth/logout";
6262
private static final String TEST_REGISTRATION_ENDPOINT = "https://test.openid.com/o/oauth/registration";
63+
private static final String TEST_DEVICE_AUTH_ENDPOINT = "https://test.openid.com/o/oauth/device";
6364
private static final String TEST_USERINFO_ENDPOINT = "https://test.openid.com/o/oauth/userinfo";
6465
private static final String TEST_JWKS_URI = "https://test.openid.com/o/oauth/jwks";
6566
private static final List<String> TEST_RESPONSE_TYPE_SUPPORTED = Arrays.asList("code", "token");
@@ -77,6 +78,7 @@ public class AuthorizationServiceConfigurationTest {
7778
+ " \"token_endpoint\": \"" + TEST_TOKEN_ENDPOINT + "\",\n"
7879
+ " \"registration_endpoint\": \"" + TEST_REGISTRATION_ENDPOINT + "\",\n"
7980
+ " \"end_session_endpoint\": \"" + TEST_END_SESSION_ENDPOINT + "\",\n"
81+
+ " \"device_authorization_endpoint\": \"" + TEST_DEVICE_AUTH_ENDPOINT + "\",\n"
8082
+ " \"userinfo_endpoint\": \"" + TEST_USERINFO_ENDPOINT + "\",\n"
8183
+ " \"jwks_uri\": \"" + TEST_JWKS_URI + "\",\n"
8284
+ " \"response_types_supported\": " + toJson(TEST_RESPONSE_TYPE_SUPPORTED) + ",\n"
@@ -127,7 +129,8 @@ public void setUp() throws Exception {
127129
Uri.parse(TEST_AUTH_ENDPOINT),
128130
Uri.parse(TEST_TOKEN_ENDPOINT),
129131
Uri.parse(TEST_REGISTRATION_ENDPOINT),
130-
Uri.parse(TEST_END_SESSION_ENDPOINT));
132+
Uri.parse(TEST_END_SESSION_ENDPOINT),
133+
Uri.parse(TEST_DEVICE_AUTH_ENDPOINT));
131134
when(mConnectionBuilder.openConnection(any(Uri.class))).thenReturn(mHttpConnection);
132135

133136
mPausedExecutorService = new PausedExecutorService();
@@ -201,6 +204,7 @@ private void assertMembers(AuthorizationServiceConfiguration config) {
201204
assertEquals(TEST_AUTH_ENDPOINT, config.authorizationEndpoint.toString());
202205
assertEquals(TEST_TOKEN_ENDPOINT, config.tokenEndpoint.toString());
203206
assertEquals(TEST_REGISTRATION_ENDPOINT, config.registrationEndpoint.toString());
207+
assertEquals(TEST_DEVICE_AUTH_ENDPOINT, config.deviceAuthorizationEndpoint.toString());
204208
assertEquals(TEST_END_SESSION_ENDPOINT, config.endSessionEndpoint.toString());
205209
}
206210

library/javatests/net/openid/appauth/AuthorizationServiceDiscoveryTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public class AuthorizationServiceDiscoveryTest {
3838
static final String TEST_TOKEN_ENDPOINT = "http://test.openid.com/o/oauth/token";
3939
static final String TEST_USERINFO_ENDPOINT = "http://test.openid.com/o/oauth/userinfo";
4040
static final String TEST_REGISTRATION_ENDPOINT = "http://test.openid.com/o/oauth/register";
41+
static final String TEST_DEVICE_AUTHORIZATION_ENDPOINT = "http://test.openid.com/o/oauth/device";
4142
static final String TEST_END_SESSION_ENDPOINT = "http://test.openid.com/o/oauth/logout";
4243
static final String TEST_JWKS_URI = "http://test.openid.com/o/oauth/jwks";
4344
static final List<String> TEST_RESPONSE_TYPES_SUPPORTED = Arrays.asList("code", "token");
@@ -54,6 +55,7 @@ public class AuthorizationServiceDiscoveryTest {
5455
TEST_TOKEN_ENDPOINT,
5556
TEST_USERINFO_ENDPOINT,
5657
TEST_REGISTRATION_ENDPOINT,
58+
TEST_DEVICE_AUTHORIZATION_ENDPOINT,
5759
TEST_END_SESSION_ENDPOINT,
5860
TEST_JWKS_URI,
5961
TEST_RESPONSE_TYPES_SUPPORTED,

0 commit comments

Comments
 (0)