Skip to content

Commit 55f6204

Browse files
Merge pull request #341 from okta/rn_validateTokenResponse
Validate TokenResponse
2 parents bfb8214 + 80b3b36 commit 55f6204

7 files changed

Lines changed: 102 additions & 9 deletions

File tree

README.md

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,6 @@ android {
8282

8383
For more details on Java 8 support for your Android projects, refer to the [Android developer documentations](#https://developer.android.com/studio/write/java8-support)
8484

85-
### Proguard
86-
87-
The SDK uses GSON for serialization. As a result, proguard/R8 obfuscation can result in incorrect behavior or crashes. To avoid issues with Proguard/R8, add the following rules to proguard-rules.pro:
88-
89-
```
90-
-keep class com.okta.oidc.** { *; }
91-
```
92-
9385
### Sample app
9486

9587
A sample is contained within this repository. For more information on how to

library/src/main/java/com/okta/oidc/net/request/TokenRequest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import androidx.annotation.Nullable;
2222
import androidx.annotation.RestrictTo;
23+
import androidx.annotation.VisibleForTesting;
2324

2425
import com.google.gson.Gson;
2526
import com.google.gson.JsonIOException;
@@ -46,6 +47,9 @@
4647
@RestrictTo(RestrictTo.Scope.LIBRARY)
4748
public class TokenRequest extends BaseRequest<TokenResponse, AuthorizationException> {
4849
private static final String TAG = TokenRequest.class.getSimpleName();
50+
@VisibleForTesting
51+
public static final String INVALID_RESPONSE_WITH_HTTP_STATUS_CODE_ERROR =
52+
"Invalid token response with status code %d";
4953

5054
private String code;
5155
private String client_assertion;
@@ -146,6 +150,7 @@ public TokenResponse executeRequest(OktaHttpClient client) throws AuthorizationE
146150
}
147151
}
148152
tokenResponse = new Gson().fromJson(json.toString(), TokenResponse.class);
153+
tokenResponse.validate();
149154
tokenResponse.setCreationTime(System.currentTimeMillis());
150155
if (tokenResponse.getIdToken() != null) {
151156
OktaIdToken idToken;
@@ -167,6 +172,15 @@ public TokenResponse executeRequest(OktaHttpClient client) throws AuthorizationE
167172
AuthorizationException.GeneralErrors.JSON_DESERIALIZATION_ERROR, ex);
168173
} catch (AuthorizationException ae) {
169174
throw ae;
175+
} catch (IllegalArgumentException e) {
176+
if (response != null) {
177+
throw new AuthorizationException(
178+
String.format(INVALID_RESPONSE_WITH_HTTP_STATUS_CODE_ERROR,
179+
response.getStatusCode()), e);
180+
} else {
181+
throw AuthorizationException.fromTemplate(AuthorizationException
182+
.GeneralErrors.NETWORK_ERROR, e);
183+
}
170184
} catch (Exception e) {
171185
throw AuthorizationException.fromTemplate(AuthorizationException
172186
.GeneralErrors.NETWORK_ERROR, e);

library/src/main/java/com/okta/oidc/net/response/TokenResponse.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@
1515

1616
package com.okta.oidc.net.response;
1717

18+
import android.text.TextUtils;
19+
1820
import androidx.annotation.NonNull;
1921
import androidx.annotation.Nullable;
2022
import androidx.annotation.RestrictTo;
23+
import androidx.annotation.VisibleForTesting;
2124

2225
import com.google.gson.Gson;
2326
import com.okta.oidc.storage.Persistable;
@@ -37,6 +40,13 @@ public class TokenResponse implements Persistable {
3740
private String id_token;
3841
private long expiresAt = -1;
3942

43+
@VisibleForTesting
44+
public static final String MISSING_ACCESS_TOKEN_ERROR = "access_token is missing";
45+
@VisibleForTesting
46+
public static final String MISSING_TOKEN_TYPE_ERROR = "token_type is missing";
47+
@VisibleForTesting
48+
public static final String MISSING_EXPIRES_IN_ERROR = "expires_in is missing";
49+
4050
@NonNull
4151
public String getAccessToken() {
4252
return access_token;
@@ -83,6 +93,18 @@ public long getExpiresAt() {
8393
return expiresAt;
8494
}
8595

96+
public void validate() throws IllegalArgumentException {
97+
if (TextUtils.isEmpty(access_token)) {
98+
throw new IllegalArgumentException(MISSING_ACCESS_TOKEN_ERROR);
99+
}
100+
if (TextUtils.isEmpty(token_type)) {
101+
throw new IllegalArgumentException(MISSING_TOKEN_TYPE_ERROR);
102+
}
103+
if (TextUtils.isEmpty(expires_in)) {
104+
throw new IllegalArgumentException(MISSING_EXPIRES_IN_ERROR);
105+
}
106+
}
107+
86108
public static final Persistable.Restore<TokenResponse> RESTORE =
87109
new Persistable.Restore<TokenResponse>() {
88110
private static final String KEY = "TokenResponse";

library/src/test/java/com/okta/oidc/net/request/TokenRequestTest.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,13 @@ public void executeRequestFailure() throws AuthorizationException {
123123
TokenResponse response = mRequest.executeRequest(mHttpClient);
124124
assertNull(response);
125125
}
126-
}
126+
127+
@Test
128+
public void executeRequestFailedValidation() throws AuthorizationException {
129+
mExpectedEx.expect(AuthorizationException.class);
130+
String jws = TestValues.getJwt(mEndPoint.getUrl(), CUSTOM_NONCE, mConfig.getClientId());
131+
mEndPoint.enqueueTokenWithMissingRequiredParams(jws);
132+
TokenResponse response = mRequest.executeRequest(mHttpClient);
133+
assertNull(response);
134+
}
135+
}

library/src/test/java/com/okta/oidc/net/response/TokenResponseTest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,17 @@
2727

2828
import static com.okta.oidc.net.response.TokenResponse.RESTORE;
2929
import static com.okta.oidc.util.JsonStrings.TOKEN_RESPONSE;
30+
import static com.okta.oidc.util.JsonStrings.TOKEN_RESPONSE_WITH_MISSING_ACCESS_TOKEN;
31+
import static com.okta.oidc.util.JsonStrings.TOKEN_RESPONSE_WITH_MISSING_EXPIRES_IN;
32+
import static com.okta.oidc.util.JsonStrings.TOKEN_RESPONSE_WITH_MISSING_TOKEN_TYPE;
3033
import static com.okta.oidc.util.TestValues.ACCESS_TOKEN;
3134
import static com.okta.oidc.util.TestValues.EXPIRES_IN;
3235
import static com.okta.oidc.util.TestValues.ID_TOKEN;
3336
import static com.okta.oidc.util.TestValues.REFRESH_TOKEN;
3437
import static com.okta.oidc.util.TestValues.SCOPES;
3538
import static com.okta.oidc.util.TestValues.TYPE_BEARER;
3639
import static org.junit.Assert.assertEquals;
40+
import static org.junit.Assert.assertThrows;
3741

3842
@RunWith(RobolectricTestRunner.class)
3943
@Config(sdk = 27)
@@ -81,6 +85,32 @@ public void getKey() {
8185
assertEquals(mToken.getKey(), RESTORE.getKey());
8286
}
8387

88+
@Test
89+
public void validatePasses() {
90+
mToken.validate();
91+
}
92+
93+
@Test
94+
public void validateThrowsExceptionWhenAccessTokenIsMissing() {
95+
mToken = RESTORE.restore(TOKEN_RESPONSE_WITH_MISSING_ACCESS_TOKEN);
96+
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, mToken::validate);
97+
assertEquals(TokenResponse.MISSING_ACCESS_TOKEN_ERROR, exception.getMessage());
98+
}
99+
100+
@Test
101+
public void validateThrowsExceptionWhenTokenTypeIsMissing() {
102+
mToken = RESTORE.restore(TOKEN_RESPONSE_WITH_MISSING_TOKEN_TYPE);
103+
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, mToken::validate);
104+
assertEquals(TokenResponse.MISSING_TOKEN_TYPE_ERROR, exception.getMessage());
105+
}
106+
107+
@Test
108+
public void validateThrowsExceptionWhenExpiresInIsMissing() {
109+
mToken = RESTORE.restore(TOKEN_RESPONSE_WITH_MISSING_EXPIRES_IN);
110+
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, mToken::validate);
111+
assertEquals(TokenResponse.MISSING_EXPIRES_IN_ERROR, exception.getMessage());
112+
}
113+
84114
@Test
85115
public void persist() {
86116
String json = mToken.persist();

library/src/test/java/com/okta/oidc/util/JsonStrings.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ public interface JsonStrings {
5858
" \"id_token\" : \"%s\"" +
5959
"}";
6060

61+
String TOKEN_MISSING_PARAMS = "{\n" +
62+
" \"scope\" : \"openid email profile\",\n" +
63+
" \"refresh_token\" : \"a9VpZDRCeFh3Nkk2VdY\",\n" +
64+
" \"id_token\" : \"%s\"" +
65+
"}";
66+
6167
String PROVIDER_CONFIG_OAUTH2 = "{\n" +
6268
" \"issuer\": \"https://dev-486177.oktapreview.com/oauth2/default/\",\n" +
6369
" \"authorization_endpoint\": \"https://dev-486177.oktapreview.com/oauth2/default/v1/authorize\",\n" +
@@ -238,6 +244,21 @@ public interface JsonStrings {
238244
"\"scope\" : \"openid profile offline_access\",\n " +
239245
"\"refresh_token\" : \"REFRESH_TOKEN\",\n\"id_token\" : \"ID_TOKEN\"\n}";
240246

247+
String TOKEN_RESPONSE_WITH_MISSING_ACCESS_TOKEN = "{ \"token_type\" : " +
248+
"\"Bearer\",\n \"expires_in\" : 3600,\n " +
249+
"\"scope\" : \"openid profile offline_access\",\n " +
250+
"\"refresh_token\" : \"REFRESH_TOKEN\",\n\"id_token\" : \"ID_TOKEN\"\n}";
251+
252+
String TOKEN_RESPONSE_WITH_MISSING_TOKEN_TYPE = "{ \"access_token\" : " +
253+
"\"ACCESS_TOKEN\",\n \"expires_in\" : 3600,\n " +
254+
"\"scope\" : \"openid profile offline_access\",\n " +
255+
"\"refresh_token\" : \"REFRESH_TOKEN\",\n\"id_token\" : \"ID_TOKEN\"\n}";
256+
257+
String TOKEN_RESPONSE_WITH_MISSING_EXPIRES_IN = "{ \"access_token\" : " +
258+
"\"ACCESS_TOKEN\",\n\"token_type\" : " +
259+
"\"Bearer\",\n \"scope\" : \"openid profile offline_access\",\n " +
260+
"\"refresh_token\" : \"REFRESH_TOKEN\",\n\"id_token\" : \"ID_TOKEN\"\n}";
261+
241262
String INVALID_CLIENT = "{\n" +
242263
" \"error\": \"invalid_client\",\n" +
243264
" \"error_description\": \"No client credentials found.\"\n" +

library/src/test/java/com/okta/oidc/util/MockEndPoint.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import static com.okta.oidc.util.JsonStrings.INVALID_CLIENT;
4949
import static com.okta.oidc.util.JsonStrings.PROVIDER_CONFIG;
5050
import static com.okta.oidc.util.JsonStrings.PROVIDER_CONFIG_OAUTH2;
51+
import static com.okta.oidc.util.JsonStrings.TOKEN_MISSING_PARAMS;
5152
import static com.okta.oidc.util.JsonStrings.TOKEN_SUCCESS;
5253
import static com.okta.oidc.util.JsonStrings.UNAUTHORIZED_INVALID_TOKEN;
5354
import static com.okta.oidc.util.JsonStrings.USER_PROFILE;
@@ -135,6 +136,10 @@ public void enqueueTokenSuccess(String idToken) {
135136
mServer.enqueue(jsonResponse(HTTP_OK, String.format(TOKEN_SUCCESS, idToken)));
136137
}
137138

139+
public void enqueueTokenWithMissingRequiredParams(String idToken) {
140+
mServer.enqueue(jsonResponse(HTTP_OK, String.format(TOKEN_MISSING_PARAMS, idToken)));
141+
}
142+
138143
public void enqueueNativeRequestSuccess(String state, int delaySeconds) {
139144
mServer.enqueue((emptyResponse(HTTP_MOVED_TEMP)
140145
.setHeadersDelay(delaySeconds, TimeUnit.SECONDS)

0 commit comments

Comments
 (0)