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

Commit c20afbe

Browse files
author
josebarrueta
committed
Merge branch '1.2.x'
2 parents 24c8768 + 803f12d commit c20afbe

File tree

11 files changed

+168
-38
lines changed

11 files changed

+168
-38
lines changed

api/src/main/java/com/stormpath/sdk/lang/Strings.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package com.stormpath.sdk.lang;
1717

1818
import java.nio.charset.Charset;
19+
import java.nio.charset.StandardCharsets;
1920
import java.util.ArrayList;
2021
import java.util.Arrays;
2122
import java.util.Collection;
@@ -1264,4 +1265,34 @@ public static String arrayToCommaDelimitedString(Object[] arr) {
12641265
return arrayToDelimitedString(arr, ",");
12651266
}
12661267

1268+
/**
1269+
* Calls {@link String#getBytes(Charset)}
1270+
*
1271+
* @param string The string to encode (if null, return null).
1272+
* @param charset The {@link Charset} to encode the <code>String</code>
1273+
* @return the encoded bytes
1274+
* @since 1.2.1
1275+
*/
1276+
private static byte[] getBytes(final String string, final Charset charset) {
1277+
if (string == null) {
1278+
return null;
1279+
}
1280+
return string.getBytes(charset);
1281+
}
1282+
1283+
/**
1284+
* Encodes the given string into a sequence of bytes using the UTF-8 charset, storing the result into a new byte
1285+
* array.
1286+
*
1287+
* @param string the String to encode, may be <code>null</code>
1288+
* @return encoded bytes, or <code>null</code> if the input string was <code>null</code>
1289+
* @throws NullPointerException Thrown if {@link StandardCharsets#UTF_8} is not initialized, which should never happen since it is
1290+
* required by the Java platform specification.
1291+
* @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
1292+
* @since 1.2.1
1293+
*/
1294+
public static byte[] getBytesUtf8(final String string) {
1295+
return getBytes(string, StandardCharsets.UTF_8);
1296+
}
1297+
12671298
}

ci/before_install.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export IS_RELEASE="$([ ${RELEASE_VERSION/SNAPSHOT} == $RELEASE_VERSION ] && [ $T
1414
export BUILD_DOCS="$([ $TRAVIS_JDK_VERSION == 'oraclejdk8' ] && echo 'true')"
1515
export RUN_ITS="$([ $TRAVIS_JDK_VERSION == 'openjdk7' ] && echo 'true')"
1616
#Install Maven 3.3.9 since Travis uses 3.2 by default
17-
wget https://archive.apache.org/dist/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.zip
17+
wget http://mirror.cc.columbia.edu/pub/software/apache/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.zip
1818
unzip -qq apache-maven-3.3.9-bin.zip
1919
export M2_HOME=$PWD/apache-maven-3.3.9
2020
export PATH=$M2_HOME/bin:$PATH

extensions/httpclient/src/test/groovy/com/stormpath/sdk/impl/application/webconfig/WebConfigurationIT.groovy

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,18 @@ import com.stormpath.sdk.application.webconfig.MeConfig
2727
import com.stormpath.sdk.application.webconfig.MeExpansionConfig
2828
import com.stormpath.sdk.application.webconfig.Oauth2Config
2929
import com.stormpath.sdk.application.webconfig.VerifyEmailConfig
30+
import com.stormpath.sdk.cache.Caches
3031
import com.stormpath.sdk.client.Client
3132
import com.stormpath.sdk.client.ClientIT
33+
import com.stormpath.sdk.client.Clients
3234
import com.stormpath.sdk.directory.Directory
35+
import com.stormpath.sdk.oauth.AccessToken
36+
import com.stormpath.sdk.oauth.Authenticators
37+
import com.stormpath.sdk.oauth.OAuthBearerRequestAuthentication
38+
import com.stormpath.sdk.oauth.OAuthPasswordGrantRequestAuthentication
39+
import com.stormpath.sdk.oauth.OAuthRequestAuthenticator
40+
import com.stormpath.sdk.oauth.OAuthRequests
41+
import com.stormpath.sdk.oauth.RefreshToken
3342
import org.testng.annotations.Test
3443

3544
import static org.testng.Assert.*
@@ -185,6 +194,42 @@ class WebConfigurationIT extends ClientIT {
185194
}
186195
}
187196

197+
@Test
198+
void testGetAccessTokenSignedWithDifferentKey() {
199+
200+
def app = createTempApp()
201+
202+
def account = createTestAccount(app)
203+
204+
OAuthPasswordGrantRequestAuthentication grantRequest = OAuthRequests.OAUTH_PASSWORD_GRANT_REQUEST.builder()
205+
.setLogin(account.email).setPassword("Changeme1!").build()
206+
207+
OAuthRequestAuthenticator authenticator = Authenticators.OAUTH_PASSWORD_GRANT_REQUEST_AUTHENTICATOR.forApplication(app)
208+
209+
def accessTokenResult = authenticator.authenticate(grantRequest)
210+
211+
def webConfigApiKey = app.getWebConfig().getSigningApiKey()
212+
213+
def client = Clients.builder().setBaseUrl(baseUrl).setCacheManager(Caches.newDisabledCacheManager()).setApiKey(webConfigApiKey).build()
214+
215+
def newClientApp = client.getResource(app.href, Application)
216+
217+
// Authenticate token against Stormpath
218+
OAuthBearerRequestAuthentication authRequest = OAuthRequests.OAUTH_BEARER_REQUEST.builder().setJwt(accessTokenResult.getAccessTokenString()).build()
219+
def authResultRemote = Authenticators.OAUTH_BEARER_REQUEST_AUTHENTICATOR.forApplication(newClientApp).authenticate(authRequest)
220+
221+
assertEquals authResultRemote.getApplication().getHref(), app.href
222+
assertEquals authResultRemote.getAccount().getHref(), account.href
223+
224+
def accessToken = client.getResource(accessTokenResult.accessTokenHref, AccessToken)
225+
226+
assertNotNull accessToken
227+
228+
def refreshToken = client.getResource(accessTokenResult.refreshToken.href, RefreshToken)
229+
230+
assertNotNull refreshToken
231+
}
232+
188233
ApiKey createTmpApiKey(Application application) {
189234
def directory = client.instantiate(Directory)
190235
directory.setName(uniquify("Admins"))

extensions/servlet/src/main/java/com/stormpath/sdk/servlet/mvc/AccessTokenController.java

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@
2222
import com.stormpath.sdk.impl.authc.DefaultBasicApiAuthenticationRequest;
2323
import com.stormpath.sdk.impl.authc.DefaultHttpServletRequestWrapper;
2424
import com.stormpath.sdk.impl.error.DefaultError;
25+
import com.stormpath.sdk.impl.oauth.DefaultIdSiteAuthenticationRequest;
2526
import com.stormpath.sdk.impl.oauth.DefaultOAuthStormpathSocialGrantRequestAuthentication;
2627
import com.stormpath.sdk.lang.Assert;
2728
import com.stormpath.sdk.oauth.AccessTokenResult;
2829
import com.stormpath.sdk.oauth.Authenticators;
30+
import com.stormpath.sdk.oauth.IdSiteAuthenticationRequest;
2931
import com.stormpath.sdk.oauth.OAuthClientCredentialsGrantRequestAuthentication;
3032
import com.stormpath.sdk.oauth.OAuthGrantRequestAuthenticationResult;
3133
import com.stormpath.sdk.oauth.OAuthPasswordGrantRequestAuthentication;
@@ -67,6 +69,7 @@ public class AccessTokenController extends AbstractController {
6769
private static final String CLIENT_CREDENTIALS_GRANT_TYPE = "client_credentials";
6870
private static final String PASSWORD_GRANT_TYPE = "password";
6971
private static final String STORMPATH_SOCIAL_GRANT_TYPE = "stormpath_social";
72+
private static final String STORMPATH_TOKEN_GRANT_TYPE = "stormpath_token";
7073
private static final String REFRESH_TOKEN_GRANT_TYPE = "refresh_token";
7174
private static final String GRANT_TYPE_PARAM_NAME = "grant_type";
7275

@@ -244,11 +247,11 @@ private AccessTokenResult refreshTokenAuthenticationRequest(HttpServletRequest r
244247
* @since 1.0.0
245248
*/
246249
private AccessTokenResult clientCredentialsAuthenticationRequest(HttpServletRequest request, HttpServletResponse response) {
247-
DefaultBasicApiAuthenticationRequest authenticationRequest = new DefaultBasicApiAuthenticationRequest(new DefaultHttpServletRequestWrapper(request));
248-
249250
OAuthGrantRequestAuthenticationResult authenticationResult;
250251

251252
try {
253+
DefaultBasicApiAuthenticationRequest authenticationRequest = new DefaultBasicApiAuthenticationRequest(new DefaultHttpServletRequestWrapper(request));
254+
252255
Application app = getApplication(request);
253256
OAuthClientCredentialsGrantRequestAuthentication clientCredentialsGrantRequestAuthentication =
254257
OAuthRequests.OAUTH_CLIENT_CREDENTIALS_GRANT_REQUEST.builder()
@@ -287,6 +290,8 @@ private AccessTokenResult stormpathSocialAuthenticationRequest(HttpServletReques
287290
} catch (ResourceException e) {
288291
log.debug("Unable to authenticate stormpath social grant request: {}", e.getMessage(), e);
289292
throw convertToOAuthException(e, OAuthErrorCode.INVALID_CLIENT);
293+
} catch (IllegalArgumentException ex) {
294+
throw new OAuthException(OAuthErrorCode.INVALID_REQUEST);
290295
}
291296

292297
return createAccessTokenResult(request, response, authenticationResult);
@@ -305,6 +310,29 @@ private OAuthException convertToOAuthException(ResourceException e, OAuthErrorCo
305310
return new OAuthException(oauthError, message);
306311
}
307312

313+
private AccessTokenResult stormpathTokenAuthenticationRequest(HttpServletRequest request, HttpServletResponse response) {
314+
OAuthGrantRequestAuthenticationResult authenticationResult;
315+
316+
try {
317+
Application app = getApplication(request);
318+
String token = request.getParameter("token");
319+
320+
IdSiteAuthenticationRequest authenticationRequest = new DefaultIdSiteAuthenticationRequest(token);
321+
322+
authenticationResult = Authenticators.ID_SITE_AUTHENTICATOR
323+
.forApplication(app)
324+
.authenticate(authenticationRequest);
325+
} catch (ResourceException e) {
326+
log.debug("Unable to authenticate stormpath token grant request: {}", e.getMessage(), e);
327+
throw convertToOAuthException(e, OAuthErrorCode.INVALID_CLIENT);
328+
} catch (IllegalArgumentException ex) {
329+
throw new OAuthException(OAuthErrorCode.INVALID_REQUEST);
330+
}
331+
332+
return createAccessTokenResult(request, response, authenticationResult);
333+
}
334+
335+
308336
@Override
309337
protected ViewModel doPost(HttpServletRequest request, HttpServletResponse response) throws Exception {
310338

@@ -350,6 +378,14 @@ protected ViewModel doPost(HttpServletRequest request, HttpServletResponse respo
350378
throw new OAuthException(OAuthErrorCode.INVALID_CLIENT);
351379
}
352380
break;
381+
case STORMPATH_TOKEN_GRANT_TYPE:
382+
try {
383+
result = this.stormpathTokenAuthenticationRequest(request, response);
384+
} catch (HttpAuthenticationException ex) {
385+
log.warn("Unable to authenticate client", ex);
386+
throw new OAuthException(OAuthErrorCode.INVALID_CLIENT);
387+
}
388+
break;
353389
default:
354390
throw new OAuthException(OAuthErrorCode.UNSUPPORTED_GRANT_TYPE, "'" + grantType + "' is an unsupported grant type.");
355391
}

extensions/spring/boot/stormpath-webmvc-spring-boot-starter/src/main/java/com/stormpath/spring/boot/autoconfigure/StormpathWebMvcAutoConfiguration.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
import com.stormpath.sdk.servlet.filter.account.JwtSigningKeyResolver;
4545
import com.stormpath.sdk.servlet.filter.oauth.AccessTokenAuthenticationRequestFactory;
4646
import com.stormpath.sdk.servlet.filter.oauth.AccessTokenResultFactory;
47+
import com.stormpath.sdk.servlet.filter.oauth.RefreshTokenAuthenticationRequestFactory;
48+
import com.stormpath.sdk.servlet.filter.oauth.RefreshTokenResultFactory;
4749
import com.stormpath.sdk.servlet.http.MediaType;
4850
import com.stormpath.sdk.servlet.http.Resolver;
4951
import com.stormpath.sdk.servlet.http.Saver;
@@ -291,6 +293,12 @@ public AccessTokenResultFactory stormpathAccessTokenResultFactory() {
291293
return super.stormpathAccessTokenResultFactory();
292294
}
293295

296+
@Bean
297+
@ConditionalOnMissingBean
298+
public RefreshTokenResultFactory stormpathRefreshTokenResultFactory() {
299+
return super.stormpathRefreshTokenResultFactory();
300+
}
301+
294302
@Bean
295303
@ConditionalOnMissingBean
296304
public WrappedServletRequestFactory stormpathWrappedServletRequestFactory() {
@@ -487,6 +495,12 @@ public AccessTokenAuthenticationRequestFactory stormpathAccessTokenAuthenticatio
487495
return super.stormpathAccessTokenAuthenticationRequestFactory();
488496
}
489497

498+
@Bean
499+
@ConditionalOnMissingBean
500+
public RefreshTokenAuthenticationRequestFactory stormpathRefreshTokenAuthenticationRequestFactory() {
501+
return super.stormpathRefreshTokenAuthenticationRequestFactory();
502+
}
503+
490504
@Bean
491505
@ConditionalOnMissingBean(name = "stormpathAccessTokenRequestAuthorizer")
492506
public RequestAuthorizer stormpathAccessTokenRequestAuthorizer() {
@@ -526,7 +540,7 @@ public Controller stormpathMeController() {
526540

527541
@Bean
528542
@ConditionalOnMissingBean
529-
public ExpandsResolver stormpathMeExpandsResolver(){
543+
public ExpandsResolver stormpathMeExpandsResolver() {
530544
return super.stormpathMeExpandsResolver();
531545
}
532546

@@ -654,7 +668,7 @@ public ControllerConfig stormpathVerifyConfig() {
654668
*/
655669
@Bean
656670
@ConditionalOnMissingBean(name = "stormpathAccessTokenConfig")
657-
public AccessTokenControllerConfig stormpathAccessTokenConfig(){
671+
public AccessTokenControllerConfig stormpathAccessTokenConfig() {
658672
return super.stormpathAccessTokenConfig();
659673
}
660674

extensions/spring/stormpath-spring-webmvc/src/main/java/com/stormpath/spring/config/StormpathWebMvcConfiguration.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
import com.stormpath.sdk.servlet.filter.account.JwtSigningKeyResolver;
4444
import com.stormpath.sdk.servlet.filter.oauth.AccessTokenAuthenticationRequestFactory;
4545
import com.stormpath.sdk.servlet.filter.oauth.AccessTokenResultFactory;
46+
import com.stormpath.sdk.servlet.filter.oauth.RefreshTokenAuthenticationRequestFactory;
47+
import com.stormpath.sdk.servlet.filter.oauth.RefreshTokenResultFactory;
4648
import com.stormpath.sdk.servlet.http.MediaType;
4749
import com.stormpath.sdk.servlet.http.Resolver;
4850
import com.stormpath.sdk.servlet.http.Saver;
@@ -246,6 +248,11 @@ public AccessTokenResultFactory stormpathAccessTokenResultFactory() {
246248
return super.stormpathAccessTokenResultFactory();
247249
}
248250

251+
@Bean
252+
public RefreshTokenResultFactory stormpathRefreshTokenResultFactory(){
253+
return super.stormpathRefreshTokenResultFactory();
254+
}
255+
249256
@Bean
250257
public WrappedServletRequestFactory stormpathWrappedServletRequestFactory() {
251258
return super.stormpathWrappedServletRequestFactory();
@@ -422,6 +429,11 @@ public AccessTokenAuthenticationRequestFactory stormpathAccessTokenAuthenticatio
422429
return super.stormpathAccessTokenAuthenticationRequestFactory();
423430
}
424431

432+
@Bean
433+
public RefreshTokenAuthenticationRequestFactory stormpathRefreshTokenAuthenticationRequestFactory(){
434+
return super.stormpathRefreshTokenAuthenticationRequestFactory();
435+
}
436+
425437
@Bean
426438
public RequestAuthorizer stormpathAccessTokenRequestAuthorizer() {
427439
return super.stormpathAccessTokenRequestAuthorizer();

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

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
import com.stormpath.sdk.tenant.Tenant;
2020
import io.jsonwebtoken.Claims;
2121
import io.jsonwebtoken.Jws;
22+
import io.jsonwebtoken.JwsHeader;
2223
import io.jsonwebtoken.Jwts;
24+
import io.jsonwebtoken.SigningKeyResolverAdapter;
2325

2426
import java.util.Date;
2527
import java.util.Map;
@@ -102,8 +104,26 @@ public void revoke() {
102104
OAuthTokenRevocators.OAUTH_TOKEN_REVOCATOR.forApplication(getApplication()).revoke(revocationRequest);
103105
}
104106

105-
protected static Jws<Claims> parseJws(String token, ApiKey apiKey) {
106-
return Jwts.parser().setSigningKey(apiKey.getSecret().getBytes(Strings.UTF_8)).parseClaimsJws(token);
107+
/**
108+
* @since 1.2.1
109+
*/
110+
protected static Jws<Claims> parseJws(String token, final InternalDataStore dataStore) {
111+
112+
final ApiKey clientApiKey = dataStore.getApiKey();
113+
114+
return Jwts.parser().setSigningKeyResolver(new SigningKeyResolverAdapter() {
115+
@Override
116+
public byte[] resolveSigningKeyBytes(JwsHeader header, Claims claims) {
117+
String keyId = header.getKeyId();
118+
119+
if (Strings.hasText(keyId) && !clientApiKey.getId().equals(keyId)) {
120+
String url = dataStore.getBaseUrl() + "/apiKeys/" + keyId;
121+
ApiKey apiKey = dataStore.getResource(url, ApiKey.class);
122+
return Strings.getBytesUtf8(apiKey.getSecret());
123+
}
124+
return Strings.getBytesUtf8(clientApiKey.getSecret());
125+
}
126+
}).parseClaimsJws(token);
107127
}
108128

109129
protected abstract TokenTypeHint getTokenTypeHint();

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@ private void ensureAccessToken() {
4747
if(isMaterialized()) {
4848
try {
4949

50-
ApiKey apiKey = getDataStore().getApiKey();
51-
JwsHeader header = AbstractBaseOAuthToken.parseJws(getString(JWT), apiKey).getHeader();
50+
JwsHeader header = AbstractBaseOAuthToken.parseJws(getString(JWT), getDataStore()).getHeader();
5251

5352
String tokenType = (String) header.get("stt");
5453
Assert.isTrue(tokenType.equals("access"));

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public RefreshToken getAsRefreshToken() {
8888
return null;
8989
}
9090

91-
Jws<Claims> jws = AbstractBaseOAuthToken.parseJws(refreshToken, getDataStore().getApiKey());
91+
Jws<Claims> jws = AbstractBaseOAuthToken.parseJws(refreshToken, getDataStore());
9292
Map<String, Object> props = new LinkedHashMap<String, Object>(1);
9393
String refreshTokenID = jws.getBody().getId();
9494
props.put("href", getDataStore().getBaseUrl() + "/refreshTokens/" + refreshTokenID);

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

Lines changed: 0 additions & 27 deletions
This file was deleted.

0 commit comments

Comments
 (0)