Skip to content
This repository was archived by the owner on Dec 12, 2018. It is now read-only.

Commit 7e23335

Browse files
committed
Resolve token validation issue in OktaAuthenticationProvider
1 parent 3d8e3a8 commit 7e23335

File tree

7 files changed

+62
-46
lines changed

7 files changed

+62
-46
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.stormpath.sdk.authc;
2+
3+
import com.stormpath.sdk.resource.Resource;
4+
5+
/**
6+
*
7+
*/
8+
public interface OktaAuthNAuthenticator extends Resource {
9+
10+
AuthenticationResult authenticate(AuthenticationRequest request);
11+
12+
void assertValidAccessToken(String accessToken);
13+
}

extensions/spring/stormpath-spring-security/src/main/java/com/stormpath/spring/config/AbstractStormpathSpringSecurityConfiguration.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
package com.stormpath.spring.config;
1717

1818
import com.stormpath.sdk.application.Application;
19+
import com.stormpath.sdk.authc.OktaAuthNAuthenticator;
20+
import com.stormpath.sdk.client.Client;
1921
import com.stormpath.spring.security.provider.AccountCustomDataPermissionResolver;
2022
import com.stormpath.spring.security.provider.AccountGrantedAuthorityResolver;
2123
import com.stormpath.spring.security.provider.AccountPermissionResolver;
@@ -47,6 +49,9 @@ public abstract class AbstractStormpathSpringSecurityConfiguration {
4749
@Autowired
4850
private Application application;
4951

52+
@Autowired
53+
private Client client;
54+
5055
public GroupGrantedAuthorityResolver stormpathGroupGrantedAuthorityResolver() {
5156
return new DefaultGroupGrantedAuthorityResolver();
5257
}
@@ -72,7 +77,7 @@ public AuthenticationProvider stormpathAuthenticationProvider() {
7277
StormpathAuthenticationProvider provider;
7378

7479
if (oktaEnabled) {
75-
provider = new OktaAuthenticationProvider(application);
80+
provider = new OktaAuthenticationProvider(application, client);
7681
}
7782
else {
7883
provider = new StormpathAuthenticationProvider(application);

extensions/spring/stormpath-spring-security/src/main/java/com/stormpath/spring/security/provider/OktaAuthenticationProvider.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,30 @@
33
import com.stormpath.sdk.account.Account;
44
import com.stormpath.sdk.application.Application;
55
import com.stormpath.sdk.authc.AuthenticationRequest;
6+
import com.stormpath.sdk.authc.OktaAuthNAuthenticator;
7+
import com.stormpath.sdk.client.Client;
68
import com.stormpath.sdk.lang.Strings;
79
import com.stormpath.sdk.oauth.AccessTokenResult;
810
import com.stormpath.sdk.resource.ResourceException;
911
import com.stormpath.spring.security.token.JwtProviderAuthenticationToken;
1012
import com.stormpath.spring.security.token.ProviderAuthenticationToken;
1113
import org.springframework.security.authentication.AuthenticationServiceException;
12-
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
1314
import org.springframework.security.core.Authentication;
1415
import org.springframework.security.core.AuthenticationException;
1516
import org.springframework.security.core.userdetails.User;
16-
import org.springframework.security.core.userdetails.UserDetails;
1717

1818
/**
1919
*
2020
*/
2121
public class OktaAuthenticationProvider extends StormpathAuthenticationProvider {
2222

2323
private final Application application;
24+
private final Client client;
2425

25-
public OktaAuthenticationProvider(Application application) {
26+
public OktaAuthenticationProvider(Application application, Client client) {
2627
super(application);
2728
this.application = application;
29+
this.client = client;
2830
}
2931

3032
@Override
@@ -38,7 +40,9 @@ public Authentication authenticate(Authentication authentication) throws Authent
3840
returnToken = authentication;
3941
}
4042
else if (authentication instanceof JwtProviderAuthenticationToken) {
41-
// FIXME: validate / exchange token
43+
// TODO: add tests around this flow
44+
OktaAuthNAuthenticator authNAuthenticator = client.instantiate(OktaAuthNAuthenticator.class);
45+
authNAuthenticator.assertValidAccessToken(((JwtProviderAuthenticationToken) authentication).getAccessToken());
4246
return authentication;
4347
}
4448
else {
@@ -72,13 +76,10 @@ else if (authentication instanceof JwtProviderAuthenticationToken) {
7276
return returnToken;
7377
}
7478

75-
7679
@Override
7780
public boolean supports(Class<?> authentication) {
7881
if (super.supports(authentication)) return true;
7982
if (JwtProviderAuthenticationToken.class.isAssignableFrom(authentication)) return true;
8083
return false;
8184
}
82-
83-
8485
}

impl/src/main/java/com/stormpath/sdk/impl/application/okta/OktaApplication.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
import com.stormpath.sdk.impl.application.DefaultApplicationAccountStoreMapping;
4343
import com.stormpath.sdk.impl.application.DefaultApplicationAccountStoreMappingList;
4444
import com.stormpath.sdk.impl.authc.DefaultUsernamePasswordRequest;
45-
import com.stormpath.sdk.impl.authc.OktaAuthNAuthenticator;
45+
import com.stormpath.sdk.impl.authc.DefaultOktaAuthNAuthenticator;
4646
import com.stormpath.sdk.impl.directory.OktaDirectory;
4747
import com.stormpath.sdk.impl.ds.InternalDataStore;
4848
import com.stormpath.sdk.impl.oauth.DefaultIdSiteAuthenticator;
@@ -264,7 +264,7 @@ public Account resetPassword(String passwordResetToken, String newPassword) {
264264
@Override
265265
public AuthenticationResult authenticateAccount(AuthenticationRequest request) throws ResourceException {
266266

267-
return new OktaAuthNAuthenticator(getDataStore()).authenticate((DefaultUsernamePasswordRequest)request);
267+
return new DefaultOktaAuthNAuthenticator(getDataStore()).authenticate((DefaultUsernamePasswordRequest)request);
268268
}
269269

270270
@Override

impl/src/main/java/com/stormpath/sdk/impl/authc/OktaAuthNAuthenticator.java renamed to impl/src/main/java/com/stormpath/sdk/impl/authc/DefaultOktaAuthNAuthenticator.java

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
import com.stormpath.sdk.account.Account;
44
import com.stormpath.sdk.api.ApiKey;
5-
import com.stormpath.sdk.api.ApiKeys;
65
import com.stormpath.sdk.application.okta.OktaTokenResponse;
76
import com.stormpath.sdk.application.okta.OktaTokenRequest;
7+
import com.stormpath.sdk.authc.AuthenticationRequest;
88
import com.stormpath.sdk.authc.AuthenticationResult;
99
import com.stormpath.sdk.authc.AuthenticationResultVisitor;
10+
import com.stormpath.sdk.authc.OktaAuthNAuthenticator;
1011
import com.stormpath.sdk.error.Error;
11-
import com.stormpath.sdk.impl.application.okta.DefaultOktaSigningKeyResolver;
1212
import com.stormpath.sdk.impl.application.okta.OktaSigningKeyResolver;
1313
import com.stormpath.sdk.impl.ds.InternalDataStore;
1414
import com.stormpath.sdk.impl.http.HttpHeaders;
@@ -21,7 +21,6 @@
2121
import io.jsonwebtoken.Jwt;
2222
import io.jsonwebtoken.Jwts;
2323
import io.jsonwebtoken.SigningKeyResolver;
24-
import org.omg.CORBA.DynAnyPackage.Invalid;
2524
import org.slf4j.Logger;
2625
import org.slf4j.LoggerFactory;
2726

@@ -34,31 +33,29 @@
3433
/**
3534
* Uses Okta's /api/v1/authn endpoint to authenticate users.
3635
*/
37-
public class OktaAuthNAuthenticator {
36+
public class DefaultOktaAuthNAuthenticator implements OktaAuthNAuthenticator {
3837

39-
private static final Logger log = LoggerFactory.getLogger(OktaAuthNAuthenticator.class);
38+
private static final Logger log = LoggerFactory.getLogger(DefaultOktaAuthNAuthenticator.class);
4039

4140
private final InternalDataStore dataStore;
4241

43-
public OktaAuthNAuthenticator(InternalDataStore dataStore) {
44-
Assert.notNull(dataStore);
42+
public DefaultOktaAuthNAuthenticator(InternalDataStore dataStore) {
4543
Assert.notNull(dataStore);
4644
this.dataStore = dataStore;
4745
}
4846

47+
@Override
48+
public AuthenticationResult authenticate(AuthenticationRequest request) {
4949

50-
public AuthenticationResult authenticate(DefaultUsernamePasswordRequest request) {
50+
Assert.isInstanceOf(DefaultUsernamePasswordRequest.class, request, "Only 'DefaultUsernamePasswordRequest' requests are supported.");
51+
DefaultUsernamePasswordRequest usernamePasswordRequest = (DefaultUsernamePasswordRequest) request;
5152

52-
final OktaTokenResponse oktaTokenResponse = doAuthRequest(request);
53+
final OktaTokenResponse oktaTokenResponse = doAuthRequest(usernamePasswordRequest);
5354

5455
// validate the key we just received
55-
SigningKeyResolver keyResolver = dataStore.instantiate(OktaSigningKeyResolver.class);
56-
final Jwt<Header, Claims> jwt = Jwts.parser()
57-
.setSigningKeyResolver(keyResolver)
58-
.parse(oktaTokenResponse.getAccessToken());
56+
final Jwt<Header, Claims> jwt = parseJwt(oktaTokenResponse.getAccessToken());
5957
String userId = jwt.getBody().get("uid", String.class);
6058

61-
6259
final String userHref = "/api/v1/users/" + userId;
6360

6461
Map<String, Object> authMap = new LinkedHashMap<>();
@@ -101,6 +98,19 @@ public String getHref() {
10198
};
10299
}
103100

101+
@Override
102+
public void assertValidAccessToken(String accessToken) {
103+
parseJwt(accessToken);
104+
}
105+
106+
private Jwt<Header, Claims> parseJwt(String accessToken) {
107+
108+
SigningKeyResolver keyResolver = dataStore.instantiate(OktaSigningKeyResolver.class);
109+
return Jwts.parser()
110+
.setSigningKeyResolver(keyResolver)
111+
.parse(accessToken);
112+
}
113+
104114
private OktaTokenResponse doAuthRequest(DefaultUsernamePasswordRequest request) {
105115
HttpHeaders httpHeaders = new HttpHeaders();
106116
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
@@ -118,6 +128,8 @@ private OktaTokenResponse doAuthRequest(DefaultUsernamePasswordRequest request)
118128
}
119129
catch (final ResourceException e) {
120130

131+
log.debug("Exception thrown while requesting token, assuming this is an Invalid username or password", e);
132+
121133
throw new ResourceException(new Error() {
122134
@Override
123135
public int getStatus() {
@@ -153,4 +165,8 @@ public String getRequestId() {
153165
}
154166
}
155167

168+
@Override
169+
public String getHref() {
170+
return null;
171+
}
156172
}

impl/src/main/java/com/stormpath/sdk/impl/oauth/DefaultIdSiteAuthenticatorFactory.java

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,25 +32,6 @@ public class DefaultIdSiteAuthenticatorFactory implements IdSiteAuthenticatorFac
3232

3333
@Override
3434
public IdSiteAuthenticator forApplication(Application application) {
35-
36-
if (application instanceof OAuthApplication) {
37-
return ((OAuthApplication) application).createIdSiteAuthenticator();
38-
}
39-
40-
// FIXME: ugly ugly ugly
41-
try {
42-
Method dataStoreMethod = AbstractResource.class.getDeclaredMethod("getDataStore");
43-
dataStoreMethod.setAccessible(true);
44-
InternalDataStore internalDataStore = (InternalDataStore) dataStoreMethod.invoke(application);
45-
46-
return new DefaultIdSiteAuthenticator(application, internalDataStore);
47-
48-
} catch (NoSuchMethodException e) {
49-
throw new UnsupportedOperationException("Could not get access to Application's 'dataStore'", e);
50-
} catch (IllegalAccessException e) {
51-
throw new UnsupportedOperationException("Could not get access to Application's 'dataStore'", e);
52-
} catch (InvocationTargetException e) {
53-
throw new UnsupportedOperationException("Could not get access to Application's 'dataStore'", e);
54-
}
35+
return ((OAuthApplication) application).createIdSiteAuthenticator();
5536
}
5637
}

impl/src/test/groovy/com/stormpath/sdk/impl/authc/OktaAuthNAuthenticatorTest.groovy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import static org.hamcrest.Matchers.*
2323
import static org.hamcrest.MatcherAssert.*
2424

2525
/**
26-
* Tests for {@link OktaAuthNAuthenticator}.
26+
* Tests for {@link DefaultOktaAuthNAuthenticator}.
2727
*/
2828
class OktaAuthNAuthenticatorTest {
2929

@@ -69,7 +69,7 @@ class OktaAuthNAuthenticatorTest {
6969

7070
replay mockDataStore, oktaTokenRequest, oktaTokenResponse, signingKeyResolver
7171

72-
def authResult = new OktaAuthNAuthenticator(mockDataStore).authenticate(authRequest)
72+
def authResult = new DefaultOktaAuthNAuthenticator(mockDataStore).authenticate(authRequest)
7373
assertThat authResult.getHref(), nullValue()
7474
assertThat authResult.getAccount(), sameInstance(account)
7575

0 commit comments

Comments
 (0)