Repository: jclouds-labs-google Updated Branches: refs/heads/master bbf953be0 -> 059a394f2
Decomplicate OAuth a little. Project: http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/repo Commit: http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/commit/059a394f Tree: http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/tree/059a394f Diff: http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/diff/059a394f Branch: refs/heads/master Commit: 059a394f2321d8d2aae43b05d12a131b78c7aec7 Parents: bbf953b Author: Adrian Cole <[email protected]> Authored: Thu Oct 30 21:05:23 2014 -0700 Committer: Adrian Cole <[email protected]> Committed: Fri Oct 31 08:50:50 2014 -0700 ---------------------------------------------------------------------- .../java/org/jclouds/oauth/v2/OAuthApi.java | 7 +- .../oauth/v2/binders/OAuthTokenBinder.java | 76 +++++++++++++++++ .../oauth/v2/domain/TokenRequestFormat.java | 45 ---------- .../v2/filters/BearerTokenAuthenticator.java | 20 ++--- .../oauth/v2/filters/OAuthAuthenticator.java | 26 +++--- .../oauth/v2/functions/BuildTokenRequest.java | 34 ++++---- .../jclouds/oauth/v2/functions/FetchToken.java | 17 ++-- .../v2/functions/OAuthCredentialsSupplier.java | 69 ++++++++------- .../v2/functions/SignOrProduceMacForToken.java | 51 ++++++----- .../oauth/v2/handlers/OAuthErrorHandler.java | 16 ++-- .../oauth/v2/handlers/OAuthTokenBinder.java | 45 ---------- .../v2/internal/SubtypeAdapterFactory.java | 42 --------- .../oauth/v2/json/JWTTokenRequestFormat.java | 89 -------------------- .../oauth/v2/binders/OAuthTokenBinderTest.java | 69 +++++++++++++++ .../v2/json/JWTTokenRequestFormatTest.java | 70 --------------- 15 files changed, 253 insertions(+), 423 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/059a394f/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApi.java ---------------------------------------------------------------------- diff --git a/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApi.java b/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApi.java index 4a12d8d..d3082fc 100644 --- a/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApi.java +++ b/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApi.java @@ -16,17 +16,18 @@ */ package org.jclouds.oauth.v2; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; + import java.io.Closeable; import javax.inject.Named; import javax.ws.rs.Consumes; import javax.ws.rs.POST; -import javax.ws.rs.core.MediaType; +import org.jclouds.oauth.v2.binders.OAuthTokenBinder; import org.jclouds.oauth.v2.config.Authentication; import org.jclouds.oauth.v2.domain.Token; import org.jclouds.oauth.v2.domain.TokenRequest; -import org.jclouds.oauth.v2.handlers.OAuthTokenBinder; import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.annotations.BinderParam; import org.jclouds.rest.annotations.Endpoint; @@ -55,6 +56,6 @@ public interface OAuthApi extends Closeable { */ @Named("authenticate") @POST - @Consumes(MediaType.APPLICATION_JSON) + @Consumes(APPLICATION_JSON) Token authenticate(@BinderParam(OAuthTokenBinder.class) TokenRequest tokenRequest) throws AuthorizationException; } http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/059a394f/oauth/src/main/java/org/jclouds/oauth/v2/binders/OAuthTokenBinder.java ---------------------------------------------------------------------- diff --git a/oauth/src/main/java/org/jclouds/oauth/v2/binders/OAuthTokenBinder.java b/oauth/src/main/java/org/jclouds/oauth/v2/binders/OAuthTokenBinder.java new file mode 100644 index 0000000..e62d9c7 --- /dev/null +++ b/oauth/src/main/java/org/jclouds/oauth/v2/binders/OAuthTokenBinder.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.oauth.v2.binders; + +import static com.google.common.base.Charsets.UTF_8; +import static com.google.common.base.Joiner.on; +import static com.google.common.io.BaseEncoding.base64Url; +import static org.jclouds.io.Payloads.newUrlEncodedFormPayload; + +import javax.inject.Inject; + +import org.jclouds.http.HttpRequest; +import org.jclouds.io.Payload; +import org.jclouds.json.Json; +import org.jclouds.oauth.v2.domain.TokenRequest; +import org.jclouds.rest.Binder; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableMultimap; + +/** + * Formats a token request into JWT format namely: + * <ol> + * <li>Transforms the token request to json.</li> + * <li>Creates the base64 header.claimset portions of the payload.</li> + * <li>Uses the provided signer function to create a signature.</li> + * <li>Creates the full url encoded payload as described in: <a href="https://developers.google.com/accounts/docs/OAuth2ServiceAccount">OAuth2ServiceAccount</a></li> + * </ol> + */ +public final class OAuthTokenBinder implements Binder { + private static final String ASSERTION_FORM_PARAM = "assertion"; + private static final String GRANT_TYPE_FORM_PARAM = "grant_type"; + private static final String GRANT_TYPE_JWT_BEARER = "urn:ietf:params:oauth:grant-type:jwt-bearer"; + + private final Function<byte[], byte[]> signer; + private final Json json; + + @Inject OAuthTokenBinder(Function<byte[], byte[]> signer, Json json) { + this.signer = signer; + this.json = json; + } + + @Override public <R extends HttpRequest> R bindToRequest(R request, Object input) { + TokenRequest tokenRequest = (TokenRequest) input; + String encodedHeader = json.toJson(tokenRequest.header()); + String encodedClaimSet = json.toJson(tokenRequest.claimSet()); + + encodedHeader = base64Url().omitPadding().encode(encodedHeader.getBytes(UTF_8)); + encodedClaimSet = base64Url().omitPadding().encode(encodedClaimSet.getBytes(UTF_8)); + + byte[] signature = signer.apply(on(".").join(encodedHeader, encodedClaimSet).getBytes(UTF_8)); + String encodedSignature = signature != null ? base64Url().omitPadding().encode(signature) : ""; + + // the final assertion in base 64 encoded {header}.{claimSet}.{signature} format + String assertion = on(".").join(encodedHeader, encodedClaimSet, encodedSignature); + Payload payload = newUrlEncodedFormPayload(ImmutableMultimap.<String, String> builder() + .put(GRANT_TYPE_FORM_PARAM, GRANT_TYPE_JWT_BEARER) + .put(ASSERTION_FORM_PARAM, assertion).build()); + + return (R) request.toBuilder().payload(payload).build(); + } +} http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/059a394f/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequestFormat.java ---------------------------------------------------------------------- diff --git a/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequestFormat.java b/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequestFormat.java deleted file mode 100644 index 7099592..0000000 --- a/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequestFormat.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jclouds.oauth.v2.domain; - -import com.google.inject.ImplementedBy; -import org.jclouds.http.HttpRequest; -import org.jclouds.oauth.v2.json.JWTTokenRequestFormat; - -import java.util.Set; - -/** - * Transforms a TokenRequest into a specific format (e.g. JWT token) - */ -@ImplementedBy(JWTTokenRequestFormat.class) -public interface TokenRequestFormat { - - /** - * Transforms the provided HttpRequest into a particular token request with a specific format. - */ - <R extends HttpRequest> R formatRequest(R httpRequest, TokenRequest tokenRequest); - - /** - * The name of the type of the token request, e.g., "JWT" - */ - String type(); - - /** - * The claims that must be present in the token request for it to be valid. - */ - Set<String> requiredClaims(); -} http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/059a394f/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenAuthenticator.java ---------------------------------------------------------------------- diff --git a/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenAuthenticator.java b/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenAuthenticator.java index 779ba44..5ff8c50 100644 --- a/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenAuthenticator.java +++ b/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenAuthenticator.java @@ -16,26 +16,24 @@ */ package org.jclouds.oauth.v2.filters; -import com.google.common.base.Supplier; +import static java.lang.String.format; + +import javax.inject.Inject; + import org.jclouds.http.HttpException; import org.jclouds.http.HttpRequest; import org.jclouds.oauth.v2.domain.OAuthCredentials; -import javax.inject.Inject; -import javax.inject.Singleton; +import com.google.common.base.Supplier; -@Singleton -public class BearerTokenAuthenticator implements OAuthAuthenticationFilter { +public final class BearerTokenAuthenticator implements OAuthAuthenticationFilter { private final Supplier<OAuthCredentials> creds; - @Inject - BearerTokenAuthenticator(final Supplier<OAuthCredentials> creds) { + @Inject BearerTokenAuthenticator(Supplier<OAuthCredentials> creds) { this.creds = creds; } - @Override - public HttpRequest filter(HttpRequest request) throws HttpException { - return request.toBuilder().addHeader("Authorization", String.format("%s %s", - "Bearer ", creds.get().credential)).build(); + @Override public HttpRequest filter(HttpRequest request) throws HttpException { + return request.toBuilder().addHeader("Authorization", format("%s %s", "Bearer ", creds.get().credential)).build(); } } http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/059a394f/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java ---------------------------------------------------------------------- diff --git a/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java b/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java index 40fc0cf..28a2c15 100644 --- a/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java +++ b/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java @@ -16,47 +16,41 @@ */ package org.jclouds.oauth.v2.filters; -import com.google.common.base.Function; -import com.google.common.cache.LoadingCache; +import static com.google.common.base.Preconditions.checkState; + +import javax.inject.Inject; + import org.jclouds.http.HttpException; import org.jclouds.http.HttpRequest; import org.jclouds.oauth.v2.domain.Token; import org.jclouds.oauth.v2.domain.TokenRequest; import org.jclouds.rest.internal.GeneratedHttpRequest; -import javax.inject.Inject; -import javax.inject.Singleton; - -import static com.google.common.base.Preconditions.checkState; +import com.google.common.base.Function; +import com.google.common.cache.LoadingCache; /** * To be used by client applications to embed an OAuth authentication in their REST requests. * <p/> * TODO when we're able to use the OAuthAuthentication an this should be used automatically */ -@Singleton -public class OAuthAuthenticator implements OAuthAuthenticationFilter { +public final class OAuthAuthenticator implements OAuthAuthenticationFilter { private Function<GeneratedHttpRequest, TokenRequest> tokenRequestBuilder; private Function<TokenRequest, Token> tokenFetcher; - @Inject - OAuthAuthenticator(Function<GeneratedHttpRequest, TokenRequest> tokenRequestBuilder, LoadingCache<TokenRequest, - Token> tokenFetcher) { + @Inject OAuthAuthenticator(Function<GeneratedHttpRequest, TokenRequest> tokenRequestBuilder, + LoadingCache<TokenRequest, Token> tokenFetcher) { this.tokenRequestBuilder = tokenRequestBuilder; this.tokenFetcher = tokenFetcher; } - @Override - public HttpRequest filter(HttpRequest request) throws HttpException { + @Override public HttpRequest filter(HttpRequest request) throws HttpException { checkState(request instanceof GeneratedHttpRequest, "request must be an instance of GeneratedHttpRequest"); GeneratedHttpRequest generatedHttpRequest = GeneratedHttpRequest.class.cast(request); TokenRequest tokenRequest = tokenRequestBuilder.apply(generatedHttpRequest); Token token = tokenFetcher.apply(tokenRequest); return request.toBuilder().addHeader("Authorization", String.format("%s %s", token.tokenType(), token.accessToken())).build(); - } - - } http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/059a394f/oauth/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java ---------------------------------------------------------------------- diff --git a/oauth/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java b/oauth/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java index 664dcab..bcce004 100644 --- a/oauth/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java +++ b/oauth/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java @@ -24,22 +24,21 @@ import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGOR import java.util.Collections; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; -import javax.inject.Singleton; - import org.jclouds.Constants; import org.jclouds.oauth.v2.config.OAuthScopes; import org.jclouds.oauth.v2.domain.ClaimSet; import org.jclouds.oauth.v2.domain.Header; import org.jclouds.oauth.v2.domain.OAuthCredentials; import org.jclouds.oauth.v2.domain.TokenRequest; -import org.jclouds.oauth.v2.domain.TokenRequestFormat; import org.jclouds.rest.internal.GeneratedHttpRequest; import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableList; import com.google.common.reflect.Invokable; import com.google.inject.Inject; import com.google.inject.name.Named; @@ -51,50 +50,47 @@ import com.google.inject.name.Named; * <p/> * TODO scopes etc should come from the REST method and not from a global property */ -@Singleton -public class BuildTokenRequest implements Function<GeneratedHttpRequest, TokenRequest> { +public final class BuildTokenRequest implements Function<GeneratedHttpRequest, TokenRequest> { + // exp and ist (expiration and emission times) are assumed mandatory already + private static final List<String> REQUIRED_CLAIMS = ImmutableList.of("iss", "scope", "aud"); private final String assertionTargetDescription; private final String signatureAlgorithm; - private final TokenRequestFormat tokenRequestFormat; private final Supplier<OAuthCredentials> credentialsSupplier; private final long tokenDuration; @Inject(optional = true) @Named(ADDITIONAL_CLAIMS) - protected Map<String, String> additionalClaims = Collections.emptyMap(); + private Map<String, String> additionalClaims = Collections.emptyMap(); @Inject(optional = true) @Named(SCOPES) - protected String globalScopes = null; + private String globalScopes = null; // injectable so expect tests can override with a predictable value @Inject(optional = true) - protected Supplier<Long> timeSourceMillisSinceEpoch = new Supplier<Long>() { + private Supplier<Long> timeSourceMillisSinceEpoch = new Supplier<Long>() { @Override public Long get() { return System.currentTimeMillis(); } }; - - @Inject - public BuildTokenRequest(@Named(AUDIENCE) String assertionTargetDescription, + + @Inject BuildTokenRequest(@Named(AUDIENCE) String assertionTargetDescription, @Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureAlgorithm, - TokenRequestFormat tokenRequestFormat, Supplier<OAuthCredentials> credentialsSupplier, + Supplier<OAuthCredentials> credentialsSupplier, @Named(Constants.PROPERTY_SESSION_INTERVAL) long tokenDuration) { this.assertionTargetDescription = assertionTargetDescription; this.signatureAlgorithm = signatureAlgorithm; - this.tokenRequestFormat = tokenRequestFormat; this.credentialsSupplier = credentialsSupplier; this.tokenDuration = tokenDuration; } - @Override - public TokenRequest apply(GeneratedHttpRequest request) { + @Override public TokenRequest apply(GeneratedHttpRequest request) { long now = timeSourceMillisSinceEpoch.get() / 1000; // fetch the token - Header header = Header.create(signatureAlgorithm, tokenRequestFormat.type()); + Header header = Header.create(signatureAlgorithm, "JWT"); Map<String, String> claims = new LinkedHashMap<String, String>(); claims.put("iss", credentialsSupplier.get().identity); @@ -102,7 +98,7 @@ public class BuildTokenRequest implements Function<GeneratedHttpRequest, TokenRe claims.put("aud", assertionTargetDescription); claims.putAll(additionalClaims); - checkState(claims.keySet().containsAll(tokenRequestFormat.requiredClaims()), + checkState(claims.keySet().containsAll(REQUIRED_CLAIMS), "not all required claims were present"); ClaimSet claimSet = ClaimSet.create(now, now + tokenDuration, Collections.unmodifiableMap(claims)); @@ -110,7 +106,7 @@ public class BuildTokenRequest implements Function<GeneratedHttpRequest, TokenRe return TokenRequest.create(header, claimSet); } - protected String getOAuthScopes(GeneratedHttpRequest request) { + private String getOAuthScopes(GeneratedHttpRequest request) { Invokable<?, ?> invokable = request.getInvocation().getInvokable(); OAuthScopes classScopes = invokable.getOwnerType().getRawType().getAnnotation(OAuthScopes.class); http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/059a394f/oauth/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java ---------------------------------------------------------------------- diff --git a/oauth/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java b/oauth/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java index 593c885..1a02cab 100644 --- a/oauth/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java +++ b/oauth/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java @@ -16,26 +16,23 @@ */ package org.jclouds.oauth.v2.functions; -import com.google.common.base.Function; +import javax.inject.Inject; + import org.jclouds.oauth.v2.OAuthApi; import org.jclouds.oauth.v2.domain.Token; import org.jclouds.oauth.v2.domain.TokenRequest; -import javax.inject.Inject; -import javax.inject.Singleton; +import com.google.common.base.Function; -@Singleton -public class FetchToken implements Function<TokenRequest, Token> { +public final class FetchToken implements Function<TokenRequest, Token> { - private OAuthApi oAuthApi; + private final OAuthApi oAuthApi; - @Inject - public FetchToken(OAuthApi oAuthApi) { + @Inject FetchToken(OAuthApi oAuthApi) { this.oAuthApi = oAuthApi; } - @Override - public Token apply(TokenRequest input) { + @Override public Token apply(TokenRequest input) { return this.oAuthApi.authenticate(input); } } http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/059a394f/oauth/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java ---------------------------------------------------------------------- diff --git a/oauth/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java b/oauth/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java index 45620c0..cd7e3d6 100644 --- a/oauth/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java +++ b/oauth/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java @@ -16,27 +16,6 @@ */ package org.jclouds.oauth.v2.functions; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Charsets; -import com.google.common.base.Supplier; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.io.ByteSource; -import com.google.common.util.concurrent.UncheckedExecutionException; -import org.jclouds.domain.Credentials; -import org.jclouds.location.Provider; -import org.jclouds.oauth.v2.domain.OAuthCredentials; -import org.jclouds.rest.AuthorizationException; - -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.security.KeyFactory; -import java.security.PrivateKey; - import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Throwables.propagate; @@ -47,20 +26,42 @@ import static org.jclouds.oauth.v2.OAuthConstants.OAUTH_ALGORITHM_NAMES_TO_KEYFA import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; import static org.jclouds.util.Throwables2.getFirstThrowableOfType; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.PrivateKey; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.domain.Credentials; +import org.jclouds.location.Provider; +import org.jclouds.oauth.v2.domain.OAuthCredentials; +import org.jclouds.rest.AuthorizationException; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Charsets; +import com.google.common.base.Supplier; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.io.ByteSource; +import com.google.common.util.concurrent.UncheckedExecutionException; + /** * Loads {@link OAuthCredentials} from a pem private key using the KeyFactory obtained from the JWT Algorithm * Name<->KeyFactory name mapping in OAuthConstants. The pem pk algorithm must match the KeyFactory algorithm. * * @see org.jclouds.oauth.v2.OAuthConstants#OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES */ -@Singleton -public class OAuthCredentialsSupplier implements Supplier<OAuthCredentials> { +@Singleton // due to cache +public final class OAuthCredentialsSupplier implements Supplier<OAuthCredentials> { private final Supplier<Credentials> creds; private final LoadingCache<Credentials, OAuthCredentials> keyCache; - @Inject - public OAuthCredentialsSupplier(@Provider Supplier<Credentials> creds, OAuthCredentialsForCredentials loader, + @Inject OAuthCredentialsSupplier(@Provider Supplier<Credentials> creds, OAuthCredentialsForCredentials loader, @Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureOrMacAlgorithm) { this.creds = creds; checkArgument(OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES.containsKey(signatureOrMacAlgorithm), @@ -74,17 +75,15 @@ public class OAuthCredentialsSupplier implements Supplier<OAuthCredentials> { * so that the private key is only recalculated once. */ @VisibleForTesting - static class OAuthCredentialsForCredentials extends CacheLoader<Credentials, OAuthCredentials> { + static final class OAuthCredentialsForCredentials extends CacheLoader<Credentials, OAuthCredentials> { private final String keyFactoryAlgorithm; - @Inject - public OAuthCredentialsForCredentials(@Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureOrMacAlgorithm) { + @Inject OAuthCredentialsForCredentials(@Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureOrMacAlgorithm) { this.keyFactoryAlgorithm = OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES.get(checkNotNull( signatureOrMacAlgorithm, "signatureOrMacAlgorithm")); } - @Override - public OAuthCredentials load(Credentials in) { + @Override public OAuthCredentials load(Credentials in) { try { String identity = in.identity; String privateKeyInPemFormat = in.credential; @@ -108,18 +107,16 @@ public class OAuthCredentialsSupplier implements Supplier<OAuthCredentials> { } } - @Override - public OAuthCredentials get() { + @Override public OAuthCredentials get() { try { // loader always throws UncheckedExecutionException so no point in using get() return keyCache.getUnchecked(checkNotNull(creds.get(), "credential supplier returned null")); } catch (UncheckedExecutionException e) { - Throwable authorizationException = getFirstThrowableOfType(e, AuthorizationException.class); + AuthorizationException authorizationException = getFirstThrowableOfType(e, AuthorizationException.class); if (authorizationException != null) { - throw (AuthorizationException) authorizationException; + throw authorizationException; } - throw propagate(e); + throw e; } } - } http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/059a394f/oauth/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java ---------------------------------------------------------------------- diff --git a/oauth/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java b/oauth/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java index 471812a..647fcfa 100644 --- a/oauth/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java +++ b/oauth/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java @@ -16,40 +16,42 @@ */ package org.jclouds.oauth.v2.functions; -import com.google.common.base.Function; -import com.google.common.base.Supplier; -import com.google.common.base.Throwables; -import org.jclouds.oauth.v2.domain.OAuthCredentials; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.base.Throwables.propagate; +import static java.lang.String.format; +import static org.jclouds.oauth.v2.OAuthConstants.NO_ALGORITHM; +import static org.jclouds.oauth.v2.OAuthConstants.OAUTH_ALGORITHM_NAMES_TO_SIGNATURE_ALGORITHM_NAMES; +import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; -import javax.annotation.PostConstruct; -import javax.crypto.Mac; -import javax.inject.Inject; -import javax.inject.Named; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.Signature; import java.security.SignatureException; -import static com.google.common.base.Preconditions.checkState; -import static java.lang.String.format; -import static org.jclouds.oauth.v2.OAuthConstants.NO_ALGORITHM; -import static org.jclouds.oauth.v2.OAuthConstants.OAUTH_ALGORITHM_NAMES_TO_SIGNATURE_ALGORITHM_NAMES; -import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; +import javax.annotation.PostConstruct; +import javax.crypto.Mac; +import javax.inject.Inject; +import javax.inject.Named; + +import org.jclouds.oauth.v2.domain.OAuthCredentials; + +import com.google.common.base.Function; +import com.google.common.base.Supplier; +import com.google.inject.Singleton; /** * Function that signs/produces mac's for OAuth tokens, provided a {@link Signature} or a {@link Mac} algorithm and * {@link PrivateKey} */ -public class SignOrProduceMacForToken implements Function<byte[], byte[]> { +@Singleton // due to signatureOrMacFunction +public final class SignOrProduceMacForToken implements Function<byte[], byte[]> { private final Supplier<OAuthCredentials> credentials; private final String signatureOrMacAlgorithm; private Function<byte[], byte[]> signatureOrMacFunction; - - @Inject - public SignOrProduceMacForToken(@Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureOrMacAlgorithm, + @Inject SignOrProduceMacForToken(@Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureOrMacAlgorithm, Supplier<OAuthCredentials> credentials) { checkState(OAUTH_ALGORITHM_NAMES_TO_SIGNATURE_ALGORITHM_NAMES.containsKey(signatureOrMacAlgorithm), format("the signature algorithm %s is not supported", signatureOrMacAlgorithm)); @@ -74,14 +76,13 @@ public class SignOrProduceMacForToken implements Function<byte[], byte[]> { } } - @Override - public byte[] apply(byte[] input) { + @Override public byte[] apply(byte[] input) { return signatureOrMacFunction.apply(input); } private static class MessageAuthenticationCodeGenerator implements Function<byte[], byte[]> { - private Mac mac; + private final Mac mac; private MessageAuthenticationCodeGenerator(String macAlgorithm, PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeyException { @@ -89,8 +90,7 @@ public class SignOrProduceMacForToken implements Function<byte[], byte[]> { this.mac.init(privateKey); } - @Override - public byte[] apply(byte[] input) { + @Override public byte[] apply(byte[] input) { this.mac.update(input); return this.mac.doFinal(); } @@ -98,7 +98,7 @@ public class SignOrProduceMacForToken implements Function<byte[], byte[]> { private static class SignatureGenerator implements Function<byte[], byte[]> { - private Signature signature; + private final Signature signature; private SignatureGenerator(String signatureAlgorithm, PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeyException { @@ -106,13 +106,12 @@ public class SignOrProduceMacForToken implements Function<byte[], byte[]> { this.signature.initSign(privateKey); } - @Override - public byte[] apply(byte[] input) { + @Override public byte[] apply(byte[] input) { try { signature.update(input); return signature.sign(); } catch (SignatureException e) { - throw Throwables.propagate(e); + throw propagate(e); } } } http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/059a394f/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java ---------------------------------------------------------------------- diff --git a/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java b/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java index 78d7844..ddc88a8 100644 --- a/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java +++ b/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java @@ -16,6 +16,9 @@ */ package org.jclouds.oauth.v2.handlers; +import static javax.ws.rs.core.Response.Status; +import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream; + import org.jclouds.http.HttpCommand; import org.jclouds.http.HttpErrorHandler; import org.jclouds.http.HttpResponse; @@ -23,17 +26,8 @@ import org.jclouds.http.HttpResponseException; import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.ResourceNotFoundException; -import javax.inject.Singleton; - -import static javax.ws.rs.core.Response.Status; -import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream; - -/** - * This will parse and set an appropriate exception on the command object. - */ -@Singleton -public class OAuthErrorHandler implements HttpErrorHandler { - public void handleError(HttpCommand command, HttpResponse response) { +public final class OAuthErrorHandler implements HttpErrorHandler { + @Override public void handleError(HttpCommand command, HttpResponse response) { // it is important to always read fully and close streams byte[] data = closeClientButKeepContentStream(response); String message = data != null ? new String(data) : null; http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/059a394f/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthTokenBinder.java ---------------------------------------------------------------------- diff --git a/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthTokenBinder.java b/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthTokenBinder.java deleted file mode 100644 index 1030804..0000000 --- a/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthTokenBinder.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jclouds.oauth.v2.handlers; - -import org.jclouds.http.HttpRequest; -import org.jclouds.oauth.v2.domain.TokenRequest; -import org.jclouds.oauth.v2.domain.TokenRequestFormat; -import org.jclouds.rest.Binder; - -import javax.inject.Inject; -import javax.inject.Singleton; - -/** - * Generic implementation of a token binder. Uses a provided {@link TokenRequestFormat} to actually bind tokens to - * requests. - */ -@Singleton -public class OAuthTokenBinder implements Binder { - - private final TokenRequestFormat tokenRequestFormat; - - @Inject - OAuthTokenBinder(TokenRequestFormat tokenRequestFormat) { - this.tokenRequestFormat = tokenRequestFormat; - } - - @Override - public <R extends HttpRequest> R bindToRequest(R request, Object input) { - return tokenRequestFormat.formatRequest(request, (TokenRequest) input); - } -} http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/059a394f/oauth/src/main/java/org/jclouds/oauth/v2/internal/SubtypeAdapterFactory.java ---------------------------------------------------------------------- diff --git a/oauth/src/main/java/org/jclouds/oauth/v2/internal/SubtypeAdapterFactory.java b/oauth/src/main/java/org/jclouds/oauth/v2/internal/SubtypeAdapterFactory.java deleted file mode 100644 index f09bea6..0000000 --- a/oauth/src/main/java/org/jclouds/oauth/v2/internal/SubtypeAdapterFactory.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jclouds.oauth.v2.internal; - -import com.google.gson.Gson; -import com.google.gson.TypeAdapter; -import com.google.gson.TypeAdapterFactory; -import com.google.gson.reflect.TypeToken; - -/** - * Type adapter used to serialize all subtypes of a value. This can be used to force serialization for an {@link - * com.google.auto.value.AutoValue} generated class. - */ -public abstract class SubtypeAdapterFactory<T> extends TypeAdapter<T> implements TypeAdapterFactory { - private final Class<T> baseClass; - - protected SubtypeAdapterFactory(Class<T> baseClass) { - this.baseClass = baseClass; - } - - /** Accepts duty for any subtype. When using AutoValue properly, this will be the generated form. */ - @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { - if (!(baseClass.isAssignableFrom(typeToken.getRawType()))) { - return null; - } - return (TypeAdapter<T>) this; - } -} http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/059a394f/oauth/src/main/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java ---------------------------------------------------------------------- diff --git a/oauth/src/main/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java b/oauth/src/main/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java deleted file mode 100644 index 41d9804..0000000 --- a/oauth/src/main/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jclouds.oauth.v2.json; - -import static com.google.common.base.Charsets.UTF_8; -import static com.google.common.base.Joiner.on; -import static com.google.common.io.BaseEncoding.base64Url; -import static org.jclouds.io.Payloads.newUrlEncodedFormPayload; - -import java.util.Set; - -import javax.inject.Inject; - -import org.jclouds.http.HttpRequest; -import org.jclouds.io.Payload; -import org.jclouds.json.Json; -import org.jclouds.oauth.v2.domain.TokenRequest; -import org.jclouds.oauth.v2.domain.TokenRequestFormat; - -import com.google.common.base.Function; -import com.google.common.collect.ImmutableMultimap; -import com.google.common.collect.ImmutableSet; - -/** - * Formats a token request into JWT format namely: - * - transforms the token request to json - * - creates the base64 header.claimset portions of the payload. - * - uses the provided signer function to create a signature - * - creates the full url encoded payload as described in: - * https://developers.google.com/accounts/docs/OAuth2ServiceAccount - * <p/> - */ -public class JWTTokenRequestFormat implements TokenRequestFormat { - - private static final String ASSERTION_FORM_PARAM = "assertion"; - private static final String GRANT_TYPE_FORM_PARAM = "grant_type"; - private static final String GRANT_TYPE_JWT_BEARER = "urn:ietf:params:oauth:grant-type:jwt-bearer"; - - private final Function<byte[], byte[]> signer; - private final Json json; - - @Inject JWTTokenRequestFormat(Function<byte[], byte[]> signer, Json json) { - this.signer = signer; - this.json = json; - } - - @Override public <R extends HttpRequest> R formatRequest(R request, TokenRequest tokenRequest) { - - String encodedHeader = json.toJson(tokenRequest.header()); - String encodedClaimSet = json.toJson(tokenRequest.claimSet()); - - encodedHeader = base64Url().omitPadding().encode(encodedHeader.getBytes(UTF_8)); - encodedClaimSet = base64Url().omitPadding().encode(encodedClaimSet.getBytes(UTF_8)); - - byte[] signature = signer.apply(on(".").join(encodedHeader, encodedClaimSet).getBytes(UTF_8)); - String encodedSignature = signature != null ? base64Url().omitPadding().encode(signature) : ""; - - // the final assertion in base 64 encoded {header}.{claimSet}.{signature} format - String assertion = on(".").join(encodedHeader, encodedClaimSet, encodedSignature); - Payload payload = newUrlEncodedFormPayload(ImmutableMultimap.<String, String> builder() - .put(GRANT_TYPE_FORM_PARAM, GRANT_TYPE_JWT_BEARER) - .put(ASSERTION_FORM_PARAM, assertion).build()); - - return (R) request.toBuilder().payload(payload).build(); - } - - @Override public String type() { - return "JWT"; - } - - @Override public Set<String> requiredClaims() { - // exp and ist (expiration and emission times) are assumed mandatory already - return ImmutableSet.of("iss", "scope", "aud"); - } -} http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/059a394f/oauth/src/test/java/org/jclouds/oauth/v2/binders/OAuthTokenBinderTest.java ---------------------------------------------------------------------- diff --git a/oauth/src/test/java/org/jclouds/oauth/v2/binders/OAuthTokenBinderTest.java b/oauth/src/test/java/org/jclouds/oauth/v2/binders/OAuthTokenBinderTest.java new file mode 100644 index 0000000..b73d49b --- /dev/null +++ b/oauth/src/test/java/org/jclouds/oauth/v2/binders/OAuthTokenBinderTest.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.oauth.v2.binders; + +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; + +import java.io.IOException; + +import org.jclouds.ContextBuilder; +import org.jclouds.http.HttpRequest; +import org.jclouds.oauth.v2.OAuthApiMetadata; +import org.jclouds.oauth.v2.OAuthTestUtils; +import org.jclouds.oauth.v2.domain.ClaimSet; +import org.jclouds.oauth.v2.domain.Header; +import org.jclouds.oauth.v2.domain.TokenRequest; +import org.jclouds.util.Strings2; +import org.testng.annotations.Test; + +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; + +@Test(groups = "unit", testName = "OAuthTokenBinderTest") +public class OAuthTokenBinderTest { + public static final String STRING_THAT_GENERATES_URL_UNSAFE_BASE64_ENCODING = "§1234567890'+±!\"#$%&/()" + + "=?*qwertyuiopº´WERTYUIOPªà sdfghjklç~ASDFGHJKLÃ^<zxcvbnm," + + ".->ZXCVBNM;:_@â¬"; + + public void testPayloadIsUrlSafe() throws IOException { + + OAuthTokenBinder tokenRequestFormat = ContextBuilder.newBuilder(new OAuthApiMetadata()).overrides + (OAuthTestUtils.defaultProperties(null)).build().utils() + .injector().getInstance(OAuthTokenBinder.class); + Header header = Header.create("a", "b"); + ClaimSet claimSet = ClaimSet.create(0, 0, + ImmutableMap.of("ist", STRING_THAT_GENERATES_URL_UNSAFE_BASE64_ENCODING)); + TokenRequest tokenRequest = TokenRequest.create(header, claimSet); + HttpRequest request = tokenRequestFormat.bindToRequest( + HttpRequest.builder().method("GET").endpoint("http://localhost").build(), tokenRequest); + + assertNotNull(request.getPayload()); + + String payload = Strings2.toStringAndClose(request.getPayload().getInput()); + + // make sure the paylod is in the format {header}.{claims}.{signature} + Iterable<String> parts = Splitter.on(".").split(payload); + + assertSame(Iterables.size(parts), 3); + + assertTrue(!payload.contains("+")); + assertTrue(!payload.contains("/")); + } +} http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/059a394f/oauth/src/test/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormatTest.java ---------------------------------------------------------------------- diff --git a/oauth/src/test/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormatTest.java b/oauth/src/test/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormatTest.java deleted file mode 100644 index bc82809..0000000 --- a/oauth/src/test/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormatTest.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jclouds.oauth.v2.json; - -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertSame; -import static org.testng.Assert.assertTrue; - -import java.io.IOException; - -import org.jclouds.ContextBuilder; -import org.jclouds.http.HttpRequest; -import org.jclouds.oauth.v2.OAuthApiMetadata; -import org.jclouds.oauth.v2.OAuthTestUtils; -import org.jclouds.oauth.v2.domain.ClaimSet; -import org.jclouds.oauth.v2.domain.Header; -import org.jclouds.oauth.v2.domain.TokenRequest; -import org.jclouds.oauth.v2.domain.TokenRequestFormat; -import org.jclouds.util.Strings2; -import org.testng.annotations.Test; - -import com.google.common.base.Splitter; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Iterables; - -@Test(groups = "unit") -public class JWTTokenRequestFormatTest { - public static final String STRING_THAT_GENERATES_URL_UNSAFE_BASE64_ENCODING = "§1234567890'+±!\"#$%&/()" + - "=?*qwertyuiopº´WERTYUIOPªà sdfghjklç~ASDFGHJKLÃ^<zxcvbnm," + - ".->ZXCVBNM;:_@â¬"; - - public void testPayloadIsUrlSafe() throws IOException { - - TokenRequestFormat tokenRequestFormat = ContextBuilder.newBuilder(new OAuthApiMetadata()).overrides - (OAuthTestUtils.defaultProperties(null)).build().utils() - .injector().getInstance(TokenRequestFormat.class); - Header header = Header.create("a", "b"); - ClaimSet claimSet = ClaimSet.create(0, 0, - ImmutableMap.of("ist", STRING_THAT_GENERATES_URL_UNSAFE_BASE64_ENCODING)); - TokenRequest tokenRequest = TokenRequest.create(header, claimSet); - HttpRequest request = tokenRequestFormat.formatRequest(HttpRequest.builder().method("GET").endpoint - ("http://localhost").build(), tokenRequest); - - assertNotNull(request.getPayload()); - - String payload = Strings2.toStringAndClose(request.getPayload().getInput()); - - // make sure the paylod is in the format {header}.{claims}.{signature} - Iterable<String> parts = Splitter.on(".").split(payload); - - assertSame(Iterables.size(parts), 3); - - assertTrue(!payload.contains("+")); - assertTrue(!payload.contains("/")); - } -}
