diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApi.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApi.java index 4a12d8d1ed..d3082fc3e2 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApi.java +++ b/apis/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; } diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/binders/OAuthTokenBinder.java similarity index 69% rename from apis/oauth/src/main/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java rename to apis/oauth/src/main/java/org/jclouds/oauth/v2/binders/OAuthTokenBinder.java index 41d98048c8..e62d9c73f3 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/binders/OAuthTokenBinder.java @@ -14,38 +14,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jclouds.oauth.v2.json; +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 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 org.jclouds.rest.Binder; 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 - *

+ *

    + *
  1. Transforms the token request to json.
  2. + *
  3. Creates the base64 header.claimset portions of the payload.
  4. + *
  5. Uses the provided signer function to create a signature.
  6. + *
  7. Creates the full url encoded payload as described in: OAuth2ServiceAccount
  8. + *
*/ -public class JWTTokenRequestFormat implements TokenRequestFormat { - +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"; @@ -53,13 +49,13 @@ public class JWTTokenRequestFormat implements TokenRequestFormat { private final Function signer; private final Json json; - @Inject JWTTokenRequestFormat(Function signer, Json json) { + @Inject OAuthTokenBinder(Function signer, Json json) { this.signer = signer; this.json = json; } - @Override public R formatRequest(R request, TokenRequest tokenRequest) { - + @Override public R bindToRequest(R request, Object input) { + TokenRequest tokenRequest = (TokenRequest) input; String encodedHeader = json.toJson(tokenRequest.header()); String encodedClaimSet = json.toJson(tokenRequest.claimSet()); @@ -72,18 +68,9 @@ public class JWTTokenRequestFormat implements TokenRequestFormat { // the final assertion in base 64 encoded {header}.{claimSet}.{signature} format String assertion = on(".").join(encodedHeader, encodedClaimSet, encodedSignature); Payload payload = newUrlEncodedFormPayload(ImmutableMultimap. builder() - .put(GRANT_TYPE_FORM_PARAM, GRANT_TYPE_JWT_BEARER) - .put(ASSERTION_FORM_PARAM, assertion).build()); + .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 requiredClaims() { - // exp and ist (expiration and emission times) are assumed mandatory already - return ImmutableSet.of("iss", "scope", "aud"); - } } diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequestFormat.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequestFormat.java deleted file mode 100644 index 7099592e01..0000000000 --- a/apis/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 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 requiredClaims(); -} diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenAuthenticator.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenAuthenticator.java index 779ba44095..5ff8c5091c 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenAuthenticator.java +++ b/apis/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 creds; - @Inject - BearerTokenAuthenticator(final Supplier creds) { + @Inject BearerTokenAuthenticator(Supplier 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(); } } diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java index 40fc0cfd37..28a2c15a5c 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java +++ b/apis/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. *

* 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 tokenRequestBuilder; private Function tokenFetcher; - @Inject - OAuthAuthenticator(Function tokenRequestBuilder, LoadingCache tokenFetcher) { + @Inject OAuthAuthenticator(Function tokenRequestBuilder, + LoadingCache 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(); - } - - } diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java index 664dcab6ea..bcce0047ad 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java +++ b/apis/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; *

* TODO scopes etc should come from the REST method and not from a global property */ -@Singleton -public class BuildTokenRequest implements Function { +public final class BuildTokenRequest implements Function { + // exp and ist (expiration and emission times) are assumed mandatory already + private static final List REQUIRED_CLAIMS = ImmutableList.of("iss", "scope", "aud"); private final String assertionTargetDescription; private final String signatureAlgorithm; - private final TokenRequestFormat tokenRequestFormat; private final Supplier credentialsSupplier; private final long tokenDuration; @Inject(optional = true) @Named(ADDITIONAL_CLAIMS) - protected Map additionalClaims = Collections.emptyMap(); + private Map 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 timeSourceMillisSinceEpoch = new Supplier() { + private Supplier timeSourceMillisSinceEpoch = new Supplier() { @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 credentialsSupplier, + Supplier 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 claims = new LinkedHashMap(); claims.put("iss", credentialsSupplier.get().identity); @@ -102,7 +98,7 @@ public class BuildTokenRequest implements Function invokable = request.getInvocation().getInvokable(); OAuthScopes classScopes = invokable.getOwnerType().getRawType().getAnnotation(OAuthScopes.class); diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java index 593c8852ec..1a02cab748 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java +++ b/apis/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 { +public final class FetchToken implements Function { - 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); } } diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java index 45620c0eb9..cd7e3d6c66 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java +++ b/apis/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 { +@Singleton // due to cache +public final class OAuthCredentialsSupplier implements Supplier { private final Supplier creds; private final LoadingCache keyCache; - @Inject - public OAuthCredentialsSupplier(@Provider Supplier creds, OAuthCredentialsForCredentials loader, + @Inject OAuthCredentialsSupplier(@Provider Supplier 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 { * so that the private key is only recalculated once. */ @VisibleForTesting - static class OAuthCredentialsForCredentials extends CacheLoader { + static final class OAuthCredentialsForCredentials extends CacheLoader { 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 { } } - @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; } } - } diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java index 471812a8b1..647fcfae26 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java +++ b/apis/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 { +@Singleton // due to signatureOrMacFunction +public final class SignOrProduceMacForToken implements Function { private final Supplier credentials; private final String signatureOrMacAlgorithm; private Function signatureOrMacFunction; - - @Inject - public SignOrProduceMacForToken(@Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureOrMacAlgorithm, + @Inject SignOrProduceMacForToken(@Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureOrMacAlgorithm, Supplier 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 { } } - @Override - public byte[] apply(byte[] input) { + @Override public byte[] apply(byte[] input) { return signatureOrMacFunction.apply(input); } private static class MessageAuthenticationCodeGenerator implements Function { - 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 { 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 { private static class SignatureGenerator implements Function { - 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 { 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); } } } diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java index 78d78440f7..ddc88a81fe 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java +++ b/apis/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; diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthTokenBinder.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthTokenBinder.java deleted file mode 100644 index 1030804714..0000000000 --- a/apis/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 bindToRequest(R request, Object input) { - return tokenRequestFormat.formatRequest(request, (TokenRequest) input); - } -} diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/internal/SubtypeAdapterFactory.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/internal/SubtypeAdapterFactory.java deleted file mode 100644 index f09bea6376..0000000000 --- a/apis/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 extends TypeAdapter implements TypeAdapterFactory { - private final Class baseClass; - - protected SubtypeAdapterFactory(Class baseClass) { - this.baseClass = baseClass; - } - - /** Accepts duty for any subtype. When using AutoValue properly, this will be the generated form. */ - @Override public TypeAdapter create(Gson gson, TypeToken typeToken) { - if (!(baseClass.isAssignableFrom(typeToken.getRawType()))) { - return null; - } - return (TypeAdapter) this; - } -} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormatTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/binders/OAuthTokenBinderTest.java similarity index 83% rename from apis/oauth/src/test/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormatTest.java rename to apis/oauth/src/test/java/org/jclouds/oauth/v2/binders/OAuthTokenBinderTest.java index bc82809cd3..b73d49bb05 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormatTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/binders/OAuthTokenBinderTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jclouds.oauth.v2.json; +package org.jclouds.oauth.v2.binders; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertSame; @@ -29,7 +29,6 @@ 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; @@ -37,23 +36,23 @@ import com.google.common.base.Splitter; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; -@Test(groups = "unit") -public class JWTTokenRequestFormatTest { +@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;:_@€"; public void testPayloadIsUrlSafe() throws IOException { - TokenRequestFormat tokenRequestFormat = ContextBuilder.newBuilder(new OAuthApiMetadata()).overrides + OAuthTokenBinder tokenRequestFormat = ContextBuilder.newBuilder(new OAuthApiMetadata()).overrides (OAuthTestUtils.defaultProperties(null)).build().utils() - .injector().getInstance(TokenRequestFormat.class); + .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.formatRequest(HttpRequest.builder().method("GET").endpoint - ("http://localhost").build(), tokenRequest); + HttpRequest request = tokenRequestFormat.bindToRequest( + HttpRequest.builder().method("GET").endpoint("http://localhost").build(), tokenRequest); assertNotNull(request.getPayload());