You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by na...@apache.org on 2015/04/15 21:41:40 UTC
[35/39] jclouds git commit: * Refactor OAuth to be less complex. *
Remove oauth as a standalone api. * Rename redundant
OAuthAuthenticationFilter to OAuthFilter. * Make AuthorizationApi more simple
by using form semantics. * Simplified OAuth by only
* Refactor OAuth to be less complex.
* Remove oauth as a standalone api.
* Rename redundant OAuthAuthenticationFilter to OAuthFilter.
* Make AuthorizationApi more simple by using form semantics.
* Simplified OAuth by only permitting RS256 and none algos.
Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/46a7351a
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/46a7351a
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/46a7351a
Branch: refs/heads/master
Commit: 46a7351a8a2c38bc191a52d8f909976d37142cb8
Parents: a35d73c
Author: Adrian Cole <ac...@twitter.com>
Authored: Mon Nov 17 19:50:48 2014 -0800
Committer: Adrian Cole <ac...@twitter.com>
Committed: Tue Nov 18 10:43:33 2014 -0800
----------------------------------------------------------------------
apis/oauth/pom.xml | 1 -
.../org/jclouds/oauth/v2/AuthorizationApi.java | 46 +++++++
.../org/jclouds/oauth/v2/JWSAlgorithms.java | 75 -----------
.../java/org/jclouds/oauth/v2/OAuthApi.java | 61 ---------
.../org/jclouds/oauth/v2/OAuthApiMetadata.java | 83 ------------
.../jclouds/oauth/v2/binders/TokenBinder.java | 77 ------------
.../jclouds/oauth/v2/config/Authorization.java | 30 +++++
.../java/org/jclouds/oauth/v2/config/OAuth.java | 35 ------
.../v2/config/OAuthAuthenticationModule.java | 46 -------
.../oauth/v2/config/OAuthHttpApiModule.java | 42 -------
.../jclouds/oauth/v2/config/OAuthModule.java | 78 ++++--------
.../oauth/v2/config/OAuthProperties.java | 10 +-
.../oauth/v2/config/PrivateKeySupplier.java | 100 +++++++++++++++
.../org/jclouds/oauth/v2/domain/Claims.java | 35 ++++--
.../org/jclouds/oauth/v2/domain/Header.java | 41 ------
.../jclouds/oauth/v2/domain/TokenRequest.java | 31 -----
.../v2/filters/BearerTokenAuthenticator.java | 40 ------
.../v2/filters/BearerTokenFromCredentials.java | 44 +++++++
.../oauth/v2/filters/JWTBearerTokenFlow.java | 113 +++++++++++++++++
.../v2/filters/OAuthAuthenticationFilter.java | 27 ----
.../oauth/v2/filters/OAuthAuthenticator.java | 51 --------
.../jclouds/oauth/v2/filters/OAuthFilter.java | 23 ++++
.../oauth/v2/functions/BuildTokenRequest.java | 92 --------------
.../oauth/v2/functions/ClaimsToAssertion.java | 87 +++++++++++++
.../jclouds/oauth/v2/functions/FetchToken.java | 38 ------
.../oauth/v2/functions/PrivateKeySupplier.java | 105 ----------------
.../v2/functions/SignOrProduceMacForToken.java | 101 ---------------
.../oauth/v2/handlers/OAuthErrorHandler.java | 58 ---------
.../oauth/v2/AuthorizationApiLiveTest.java | 94 ++++++++++++++
.../oauth/v2/AuthorizationApiMockTest.java | 125 ++++++++++++++++++
.../jclouds/oauth/v2/OAuthApiMetadataTest.java | 39 ------
.../oauth/v2/binders/TokenBinderTest.java | 85 -------------
.../oauth/v2/config/PrivateKeySupplierTest.java | 67 ++++++++++
.../oauth/v2/features/OAuthApiLiveTest.java | 84 -------------
.../oauth/v2/features/OAuthApiMockTest.java | 126 -------------------
.../v2/functions/ClaimsToAssertionTest.java | 48 +++++++
.../v2/functions/PrivateKeySupplierTest.java | 83 ------------
.../oauth/v2/functions/SignerFunctionTest.java | 56 ---------
.../v2/handlers/OAuthErrorHandlerTest.java | 92 --------------
.../oauth/v2/internal/Base64UrlSafeTest.java | 40 ------
.../oauth/v2/internal/BaseOAuthApiLiveTest.java | 63 ----------
.../BaseOAuthAuthenticatedApiLiveTest.java | 112 -----------------
.../jclouds/oauth/v2/parse/ParseTokenTest.java | 40 ------
.../oauth/src/test/resources/tokenResponse.json | 5 -
44 files changed, 832 insertions(+), 1897 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/pom.xml
----------------------------------------------------------------------
diff --git a/apis/oauth/pom.xml b/apis/oauth/pom.xml
index 9f83ac8..f978213 100644
--- a/apis/oauth/pom.xml
+++ b/apis/oauth/pom.xml
@@ -35,7 +35,6 @@
<test.oauth.identity>FIX_ME</test.oauth.identity>
<test.oauth.credential>FIX_ME</test.oauth.credential>
<test.oauth.endpoint>FIX_ME</test.oauth.endpoint>
- <test.jclouds.oauth.jws-alg>RS256</test.jclouds.oauth.jws-alg>
<test.jclouds.oauth.audience>FIX_ME</test.jclouds.oauth.audience>
<test.jclouds.oauth.scope>FIX_ME</test.jclouds.oauth.scope>
<test.oauth.api-version>2</test.oauth.api-version>
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/AuthorizationApi.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/AuthorizationApi.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/AuthorizationApi.java
new file mode 100644
index 0000000..0a9d453
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/AuthorizationApi.java
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+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.FormParam;
+import javax.ws.rs.POST;
+
+import org.jclouds.oauth.v2.functions.ClaimsToAssertion;
+import org.jclouds.oauth.v2.config.Authorization;
+import org.jclouds.oauth.v2.domain.Claims;
+import org.jclouds.oauth.v2.domain.Token;
+import org.jclouds.rest.annotations.Endpoint;
+import org.jclouds.rest.annotations.FormParams;
+import org.jclouds.rest.annotations.ParamParser;
+
+/**
+ * Binds to an OAuth2 <a href="http://tools.ietf.org/html/rfc6749#section-3.1">authorization endpoint</a>.
+ */
+@Endpoint(Authorization.class)
+public interface AuthorizationApi extends Closeable {
+ @Named("oauth2:authorize")
+ @POST
+ @FormParams(keys = "grant_type", values = "urn:ietf:params:oauth:grant-type:jwt-bearer")
+ @Consumes(APPLICATION_JSON)
+ Token authorize(@FormParam("assertion") @ParamParser(ClaimsToAssertion.class) Claims claims);
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/JWSAlgorithms.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/JWSAlgorithms.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/JWSAlgorithms.java
deleted file mode 100644
index 072fc53..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/JWSAlgorithms.java
+++ /dev/null
@@ -1,75 +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;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.security.KeyFactory;
-import java.security.NoSuchAlgorithmException;
-import java.util.List;
-
-import com.google.common.collect.ImmutableList;
-
-/**
- * JSON Web Signature Algorithms
- * <p/>
- * We only support <a href="http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-36#section-3.1">required
- * or recommended algorithms</a>, with the exception of {@code none}, which is only supported in tests.
- */
-public final class JWSAlgorithms {
- /** This is a marker algorithm only supported in tests. */
- public static final String NONE = "none";
-
- private static final List<String> SUPPORTED_ALGS = ImmutableList.of("ES256", "RS256", "HS256", NONE);
-
- /**
- * Static mapping between the oauth algorithm name and the Crypto provider signature algorithm name and KeyFactory.
- */
- private static final List<List<String>> ALG_TO_SIGNATURE_ALG_AND_KEY_FACTORY = ImmutableList.<List<String>>of( //
- ImmutableList.of(SUPPORTED_ALGS.get(0), "SHA256withECDSA", "EC"), // ECDSA using P-256 and SHA-256
- ImmutableList.of(SUPPORTED_ALGS.get(1), "SHA256withRSA", "RSA"), // RSASSA-PKCS-v1_5 using SHA-256
- ImmutableList.of(SUPPORTED_ALGS.get(2), "HmacSHA256", "DiffieHellman") // HMAC using SHA-256
- );
-
- /** Ordered list of supported algorithms by recommendation. */
- public static List<String> supportedAlgs() {
- return SUPPORTED_ALGS;
- }
-
- public static String macOrSignature(String jwsAlg) {
- return ALG_TO_SIGNATURE_ALG_AND_KEY_FACTORY.get(indexOf(jwsAlg)).get(1);
- }
-
- public static KeyFactory keyFactory(String jwsAlg) {
- String keyFactoryAlgorithm = ALG_TO_SIGNATURE_ALG_AND_KEY_FACTORY.get(indexOf(jwsAlg)).get(2);
- try {
- return KeyFactory.getInstance(keyFactoryAlgorithm);
- } catch (NoSuchAlgorithmException e) {
- throw new AssertionError("Invalid contents in JWSAlgorithms! " + e.getMessage());
- }
- }
-
- private static int indexOf(String jwsAlg) {
- int result = SUPPORTED_ALGS.indexOf(checkNotNull(jwsAlg, "jwsAlg"));
- checkArgument(result != -1, "JSON Web Signature alg %s is not in the supported list %s", jwsAlg, SUPPORTED_ALGS);
- return result;
- }
-
- private JWSAlgorithms() {
- }
-}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApi.java
----------------------------------------------------------------------
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
deleted file mode 100644
index 770e5e8..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApi.java
+++ /dev/null
@@ -1,61 +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;
-
-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 org.jclouds.oauth.v2.binders.TokenBinder;
-import org.jclouds.oauth.v2.config.OAuth;
-import org.jclouds.oauth.v2.domain.Token;
-import org.jclouds.oauth.v2.domain.TokenRequest;
-import org.jclouds.rest.AuthorizationException;
-import org.jclouds.rest.annotations.BinderParam;
-import org.jclouds.rest.annotations.Endpoint;
-
-/**
- * Provides access to OAuth via REST api.
- * <p/>
- * Usually this is not directly used by a client, which instead specifies
- * OAuthAuthenticator as a request filter, which in turn uses this class to
- * perform token requests.
- */
-@Endpoint(OAuth.class)
-public interface OAuthApi extends Closeable {
-
- /**
- * Authenticates/Authorizes access to a resource defined in TokenRequest
- * against an OAuth v2 authentication/authorization server.
- *
- * @param tokenRequest
- * specified the principal and the required permissions
- * @return a Token object with the token required to access the resource
- * along with its expiration time
- * @throws AuthorizationException
- * if the principal cannot be authenticated or has no permissions
- * for the specifed resources.
- */
- @Named("authenticate")
- @POST
- @Consumes(APPLICATION_JSON)
- Token authenticate(@BinderParam(TokenBinder.class) TokenRequest tokenRequest) throws AuthorizationException;
-}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java
deleted file mode 100644
index 66f61bb..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java
+++ /dev/null
@@ -1,83 +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;
-
-import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
-import static org.jclouds.oauth.v2.config.CredentialType.P12_PRIVATE_KEY_CREDENTIALS;
-import static org.jclouds.oauth.v2.config.OAuthProperties.CREDENTIAL_TYPE;
-import static org.jclouds.oauth.v2.config.OAuthProperties.JWS_ALG;
-
-import java.net.URI;
-import java.util.Properties;
-
-import org.jclouds.apis.ApiMetadata;
-import org.jclouds.oauth.v2.config.OAuthHttpApiModule;
-import org.jclouds.oauth.v2.config.OAuthModule;
-import org.jclouds.rest.internal.BaseHttpApiMetadata;
-
-import com.google.auto.service.AutoService;
-import com.google.common.collect.ImmutableSet;
-import com.google.inject.Module;
-
-@AutoService(ApiMetadata.class)
-public class OAuthApiMetadata extends BaseHttpApiMetadata<OAuthApi> {
-
- @Override
- public Builder toBuilder() {
- return new Builder().fromApiMetadata(this);
- }
-
- public OAuthApiMetadata() {
- this(new Builder());
- }
-
- protected OAuthApiMetadata(Builder builder) {
- super(builder);
- }
-
- public static Properties defaultProperties() {
- Properties properties = BaseHttpApiMetadata.defaultProperties();
- properties.put(JWS_ALG, "RS256");
- properties.put(CREDENTIAL_TYPE, P12_PRIVATE_KEY_CREDENTIALS);
- properties.put(PROPERTY_SESSION_INTERVAL, 3600);
- return properties;
- }
-
- public static class Builder extends BaseHttpApiMetadata.Builder<OAuthApi, Builder> {
-
- protected Builder() {
- id("oauth")
- .name("OAuth API")
- .identityName("service_account")
- .credentialName("service_key")
- .documentation(URI.create("TODO"))
- .version("2")
- .defaultProperties(OAuthApiMetadata.defaultProperties())
- .defaultModules(ImmutableSet.<Class<? extends Module>>of(OAuthModule.class, OAuthHttpApiModule.class));
- }
-
- @Override
- public OAuthApiMetadata build() {
- return new OAuthApiMetadata(this);
- }
-
- @Override
- protected Builder self() {
- return this;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/binders/TokenBinder.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/binders/TokenBinder.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/binders/TokenBinder.java
deleted file mode 100644
index 0782000..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/binders/TokenBinder.java
+++ /dev/null
@@ -1,77 +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.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.base.Supplier;
-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 TokenBinder 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 Supplier<Function<byte[], byte[]>> signer;
- private final Json json;
-
- @Inject TokenBinder(Supplier<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.get().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/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authorization.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authorization.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authorization.java
new file mode 100644
index 0000000..cefc5ac
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authorization.java
@@ -0,0 +1,30 @@
+/*
+ * 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.config;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.inject.Qualifier;
+
+@Retention(value = RetentionPolicy.RUNTIME)
+@Target(value = {ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
+@Qualifier
+public @interface Authorization {
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuth.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuth.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuth.java
deleted file mode 100644
index 6255e50..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuth.java
+++ /dev/null
@@ -1,35 +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.config;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-import javax.inject.Qualifier;
-
-/**
- * Qualifies OAuth related resources, such as Endpoint.
- *
- * @see org.jclouds.oauth.v2.OAuthApi
- */
-@Retention(value = RetentionPolicy.RUNTIME)
-@Target(value = {ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
-@Qualifier
-public @interface OAuth {
-}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthAuthenticationModule.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthAuthenticationModule.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthAuthenticationModule.java
deleted file mode 100644
index 4d238f1..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthAuthenticationModule.java
+++ /dev/null
@@ -1,46 +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.config;
-
-import static org.jclouds.rest.config.BinderUtils.bindHttpApi;
-
-import java.net.URI;
-
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.jclouds.oauth.v2.OAuthApi;
-
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.inject.AbstractModule;
-import com.google.inject.Provides;
-
-public class OAuthAuthenticationModule extends AbstractModule {
-
- @Override
- protected void configure() {
- bindHttpApi(binder(), OAuthApi.class);
- }
-
- @Provides
- @Singleton
- @OAuth
- protected Supplier<URI> oauthEndpoint(@Named("oauth.endpoint") String endpoint) {
- return Suppliers.ofInstance(URI.create(endpoint));
- }
-}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthHttpApiModule.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthHttpApiModule.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthHttpApiModule.java
deleted file mode 100644
index 5a1d5d2..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthHttpApiModule.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.config;
-
-import java.net.URI;
-
-import javax.inject.Singleton;
-
-import org.jclouds.oauth.v2.OAuthApi;
-import org.jclouds.providers.ProviderMetadata;
-import org.jclouds.rest.ConfiguresHttpApi;
-import org.jclouds.rest.config.HttpApiModule;
-
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.inject.Provides;
-
-/** Api module to when accessing OAuth stand-alone. */
-@ConfiguresHttpApi
-public class OAuthHttpApiModule extends HttpApiModule<OAuthApi> {
-
- @Provides
- @Singleton
- @OAuth
- protected Supplier<URI> provideAuthenticationEndpoint(ProviderMetadata providerMetadata) {
- return Suppliers.ofInstance(URI.create(providerMetadata.getEndpoint()));
- }
-}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthModule.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthModule.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthModule.java
index e6d5985..8a3568c 100644
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthModule.java
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthModule.java
@@ -16,82 +16,48 @@
*/
package org.jclouds.oauth.v2.config;
-import static java.util.concurrent.TimeUnit.SECONDS;
-import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
-import static org.jclouds.oauth.v2.JWSAlgorithms.NONE;
-import static org.jclouds.oauth.v2.config.OAuthProperties.JWS_ALG;
+import static org.jclouds.oauth.v2.config.CredentialType.P12_PRIVATE_KEY_CREDENTIALS;
+import static org.jclouds.oauth.v2.config.OAuthProperties.CREDENTIAL_TYPE;
+import static org.jclouds.rest.config.BinderUtils.bindHttpApi;
+import java.net.URI;
import java.security.PrivateKey;
-import org.jclouds.http.HttpRequest;
-import org.jclouds.oauth.v2.domain.Token;
-import org.jclouds.oauth.v2.domain.TokenRequest;
-import org.jclouds.oauth.v2.filters.BearerTokenAuthenticator;
-import org.jclouds.oauth.v2.filters.OAuthAuthenticationFilter;
-import org.jclouds.oauth.v2.filters.OAuthAuthenticator;
-import org.jclouds.oauth.v2.functions.BuildTokenRequest;
-import org.jclouds.oauth.v2.functions.FetchToken;
-import org.jclouds.oauth.v2.functions.PrivateKeySupplier;
-import org.jclouds.oauth.v2.functions.SignOrProduceMacForToken;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.oauth.v2.AuthorizationApi;
+import org.jclouds.oauth.v2.filters.BearerTokenFromCredentials;
+import org.jclouds.oauth.v2.filters.JWTBearerTokenFlow;
+import org.jclouds.oauth.v2.filters.OAuthFilter;
-import com.google.common.base.Function;
-import com.google.common.base.Functions;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Provides;
-import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
-import com.google.inject.name.Named;
-public class OAuthModule extends AbstractModule {
+public final class OAuthModule extends AbstractModule {
@Override protected void configure() {
+ bindHttpApi(binder(), AuthorizationApi.class);
bind(CredentialType.class).toProvider(CredentialTypeFromPropertyOrDefault.class);
- bind(new TypeLiteral<Function<HttpRequest, TokenRequest>>() {}).to(BuildTokenRequest.class);
- bind(new TypeLiteral<Function<TokenRequest, Token>>() {}).to(FetchToken.class);
- bind(new TypeLiteral<Supplier<PrivateKey>>() {}).annotatedWith(OAuth.class).to(PrivateKeySupplier.class);
+ bind(new TypeLiteral<Supplier<PrivateKey>>() {}).annotatedWith(Authorization.class).to(PrivateKeySupplier.class);
}
- /**
- * Provides a cache for tokens. Cache is time based and by default expires after 59 minutes
- * (the maximum time a token is valid is 60 minutes).
- * This cache and expiry period is system-wide and does not attend to per-instance expiry time
- * (e.g. "expires_in" from Google Compute -- which is set to the standard 3600 seconds).
- */
- // NB: If per-instance expiry time is required, significant refactoring will be needed.
@Provides
- @Singleton
- public LoadingCache<TokenRequest, Token> provideAccessCache(Function<TokenRequest, Token> getAccess,
- @Named(PROPERTY_SESSION_INTERVAL) long expirationSeconds) {
- // since the session interval is also the token expiration time requested to the server make the token expire a
- // bit before the deadline to make sure there aren't session expiration exceptions
- expirationSeconds = expirationSeconds > 30 ? expirationSeconds - 30 : expirationSeconds;
- return CacheBuilder.newBuilder().expireAfterWrite(expirationSeconds, SECONDS).build(CacheLoader.from(getAccess));
- }
-
- /**
- * Defers instantiation of {@linkplain SignOrProduceMacForToken} so as to avoid requiring private keys when the alg
- * is set to {@linkplain org.jclouds.oauth.v2.JWSAlgorithms#NONE}.
- */
- @Provides @Singleton Supplier<Function<byte[], byte[]>> signOrProduceMacForToken(@Named(JWS_ALG) String jwsAlg,
- Provider<SignOrProduceMacForToken> in) {
- if (jwsAlg.equals(NONE)) { // Current implementation requires we return null on none.
- return (Supplier) Suppliers.ofInstance(Functions.constant(null));
- }
- return Suppliers.memoize(in.get());
+ @Authorization
+ protected Supplier<URI> oauthEndpoint(@javax.inject.Named("oauth.endpoint") String endpoint) {
+ return Suppliers.ofInstance(URI.create(endpoint));
}
@Singleton
public static class CredentialTypeFromPropertyOrDefault implements Provider<CredentialType> {
@Inject(optional = true)
- @Named(OAuthProperties.CREDENTIAL_TYPE)
- String credentialType = CredentialType.P12_PRIVATE_KEY_CREDENTIALS.toString();
+ @Named(CREDENTIAL_TYPE)
+ String credentialType = P12_PRIVATE_KEY_CREDENTIALS.toString();
@Override
public CredentialType get() {
@@ -101,9 +67,9 @@ public class OAuthModule extends AbstractModule {
@Provides
@Singleton
- protected OAuthAuthenticationFilter authenticationFilterForCredentialType(CredentialType credentialType,
- OAuthAuthenticator serviceAccountAuth,
- BearerTokenAuthenticator bearerTokenAuth) {
+ protected OAuthFilter authenticationFilterForCredentialType(CredentialType credentialType,
+ JWTBearerTokenFlow serviceAccountAuth,
+ BearerTokenFromCredentials bearerTokenAuth) {
switch (credentialType) {
case P12_PRIVATE_KEY_CREDENTIALS:
return serviceAccountAuth;
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java
index 197bc31..7faed0c 100644
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java
@@ -16,18 +16,16 @@
*/
package org.jclouds.oauth.v2.config;
-import org.jclouds.oauth.v2.JWSAlgorithms;
+public final class OAuthProperties {
-public class OAuthProperties {
-
- /** The JSON Web Signature alg, from the {@link JWSAlgorithms#supportedAlgs() supported list}. */
+ /** The JSON Web Signature alg, must be {@code RS256} or {@code none}. */
public static final String JWS_ALG = "jclouds.oauth.jws-alg";
/**
* The oauth audience, who this token is intended for. For instance in JWT and for
* google API's this property maps to: {"aud","https://accounts.google.com/o/oauth2/token"}
*
- * @see <a href="http://tools.ietf.org/html/draft-jones-json-web-token-04">doc</a>
+ * @see <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-30">doc</a>
*/
public static final String AUDIENCE = "jclouds.oauth.audience";
@@ -38,4 +36,6 @@ public class OAuthProperties {
*/
public static final String CREDENTIAL_TYPE = "jclouds.oauth.credential-type";
+ private OAuthProperties() {
+ }
}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/PrivateKeySupplier.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/PrivateKeySupplier.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/PrivateKeySupplier.java
new file mode 100644
index 0000000..4873dc9
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/PrivateKeySupplier.java
@@ -0,0 +1,100 @@
+/*
+ * 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.config;
+
+import static com.google.common.base.Charsets.UTF_8;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Throwables.propagate;
+import static org.jclouds.crypto.Pems.privateKeySpec;
+import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
+
+import java.io.IOException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.spec.InvalidKeySpecException;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.domain.Credentials;
+import org.jclouds.location.Provider;
+import org.jclouds.rest.AuthorizationException;
+
+import com.google.common.annotations.VisibleForTesting;
+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 PrivateKey} from a pem private key using and RSA KeyFactory. The pem pk algorithm must match the
+ * KeyFactory algorithm.
+ */
+@Singleton // due to cache
+final class PrivateKeySupplier implements Supplier<PrivateKey> {
+
+ private final Supplier<Credentials> creds;
+ private final LoadingCache<Credentials, PrivateKey> keyCache;
+
+ @Inject PrivateKeySupplier(@Provider Supplier<Credentials> creds, PrivateKeyForCredentials loader) {
+ this.creds = creds;
+ // throw out the private key related to old credentials
+ this.keyCache = CacheBuilder.newBuilder().maximumSize(2).build(checkNotNull(loader, "loader"));
+ }
+
+ /**
+ * it is relatively expensive to extract a private key from a PEM. cache the relationship between current
+ * credentials
+ * so that the private key is only recalculated once.
+ */
+ @VisibleForTesting
+ static final class PrivateKeyForCredentials extends CacheLoader<Credentials, PrivateKey> {
+
+ @Override public PrivateKey load(Credentials in) {
+ try {
+ String privateKeyInPemFormat = checkNotNull(in.credential, "credential in PEM format");
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ return keyFactory.generatePrivate(privateKeySpec(ByteSource.wrap(privateKeyInPemFormat.getBytes(UTF_8))));
+ } catch (NoSuchAlgorithmException e) {
+ throw new AssertionError(e);
+ } catch (IOException e) {
+ throw propagate(e);
+ } catch (InvalidKeySpecException e) {
+ throw new AuthorizationException("security exception loading credentials. " + e.getMessage(), e);
+ // catch IAE that is thrown when parsing the pk fails
+ } catch (IllegalArgumentException e) {
+ throw new AuthorizationException("cannot parse pk. " + e.getMessage(), e);
+ }
+ }
+ }
+
+ @Override public PrivateKey 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) {
+ AuthorizationException authorizationException = getFirstThrowableOfType(e, AuthorizationException.class);
+ if (authorizationException != null) {
+ throw authorizationException;
+ }
+ throw e;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Claims.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Claims.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Claims.java
index 07b03f6..9087acd 100644
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Claims.java
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Claims.java
@@ -16,19 +16,40 @@
*/
package org.jclouds.oauth.v2.domain;
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+
/**
- * Description of Claims corresponding to a {@linkplain Token JWT Token}.
+ * Claims corresponding to a {@linkplain Token JWT Token}.
*
* @see <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-30#section-4">registered list</a>
*/
-public final class Claims {
+@AutoValue
+public abstract class Claims {
+ /** The issuer of this token. In google, the service account email. */
+ public abstract String iss();
+
+ /** A comma-separated list of scopes needed to perform the request. */
+ public abstract String scope();
+
+ /**
+ * The oauth audience, who this token is intended for. For instance in JWT and for
+ * google API's, this maps to: {@code https://accounts.google.com/o/oauth2/token}
+ */
+ public abstract String aud();
+
+ /** The expiration time, in seconds since {@link #iat()}. */
+ public abstract long exp();
+
/** The time at which the JWT was issued, in seconds since the epoch. */
- public static final String ISSUED_AT = "iat";
+ public abstract long iat();
- /** The expiration time, in seconds since {@link #ISSUED_AT}. */
- public static final String EXPIRATION_TIME = "exp";
+ @SerializedNames({ "iss", "scope", "aud", "exp", "iat" })
+ public static Claims create(String iss, String scope, String aud, long exp, long iat) {
+ return new AutoValue_Claims(iss, scope, aud, exp, iat);
+ }
- private Claims(){
- throw new AssertionError("intentionally unimplemented");
+ Claims() {
}
}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Header.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Header.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Header.java
deleted file mode 100644
index 9cdd924..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Header.java
+++ /dev/null
@@ -1,41 +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 org.jclouds.json.SerializedNames;
-
-import com.google.auto.value.AutoValue;
-
-/**
- * The header for the OAuth token, contains the signer algorithm's name and the type of the token
- *
- * @see <a href="https://developers.google.com/accounts/docs/OAuth2ServiceAccount">doc</a>
- */
-@AutoValue
-public abstract class Header {
-
- /** The name of the algorithm used to compute the signature, e.g., {@code ES256}. */
- public abstract String signerAlgorithm();
-
- /** The type of the token, e.g., {@code JWT}. */
- public abstract String type();
-
- @SerializedNames({ "alg", "typ" })
- public static Header create(String signerAlgorithm, String type){
- return new AutoValue_Header(signerAlgorithm, type);
- }
-}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequest.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequest.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequest.java
deleted file mode 100644
index b08a20b..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequest.java
+++ /dev/null
@@ -1,31 +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 java.util.Map;
-
-import com.google.auto.value.AutoValue;
-
-@AutoValue
-public abstract class TokenRequest {
- public abstract Header header();
- public abstract Map<String, Object> claimSet();
-
- public static TokenRequest create(Header header, Map<String, Object> claims) {
- return new AutoValue_TokenRequest(header, claims);
- }
-}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenAuthenticator.java
----------------------------------------------------------------------
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
deleted file mode 100644
index 3d7d92d..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenAuthenticator.java
+++ /dev/null
@@ -1,40 +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.filters;
-
-import static java.lang.String.format;
-
-import javax.inject.Inject;
-
-import org.jclouds.domain.Credentials;
-import org.jclouds.http.HttpException;
-import org.jclouds.http.HttpRequest;
-import org.jclouds.location.Provider;
-
-import com.google.common.base.Supplier;
-
-public final class BearerTokenAuthenticator implements OAuthAuthenticationFilter {
- private final Supplier<Credentials> creds;
-
- @Inject BearerTokenAuthenticator(@Provider Supplier<Credentials> creds) {
- this.creds = creds;
- }
-
- @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/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenFromCredentials.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenFromCredentials.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenFromCredentials.java
new file mode 100644
index 0000000..61eacf1
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenFromCredentials.java
@@ -0,0 +1,44 @@
+/*
+ * 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.filters;
+
+import static java.lang.String.format;
+
+import javax.inject.Inject;
+
+import org.jclouds.domain.Credentials;
+import org.jclouds.http.HttpException;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.location.Provider;
+
+import com.google.common.base.Supplier;
+
+/**
+ * When the user supplies {@link org.jclouds.oauth.v2.config.CredentialType#BEARER_TOKEN_CREDENTIALS}, the credential
+ * is a literal bearer token. This filter applies that to the request.
+ */
+public final class BearerTokenFromCredentials implements OAuthFilter {
+ private final Supplier<Credentials> creds;
+
+ @Inject BearerTokenFromCredentials(@Provider Supplier<Credentials> creds) {
+ this.creds = creds;
+ }
+
+ @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/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/JWTBearerTokenFlow.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/JWTBearerTokenFlow.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/JWTBearerTokenFlow.java
new file mode 100644
index 0000000..466c8e3
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/JWTBearerTokenFlow.java
@@ -0,0 +1,113 @@
+/*
+ * 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.filters;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
+import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.jclouds.domain.Credentials;
+import org.jclouds.http.HttpException;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.location.Provider;
+import org.jclouds.oauth.v2.AuthorizationApi;
+import org.jclouds.oauth.v2.config.OAuthScopes;
+import org.jclouds.oauth.v2.domain.Claims;
+import org.jclouds.oauth.v2.domain.Token;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Supplier;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+
+/**
+ * Authorizes new Bearer Tokens at runtime by authorizing claims needed for the http request.
+ *
+ * <h3>Cache</h3>
+ * This maintains a time-based Bearer Token cache. By default expires after 59 minutes
+ * (the maximum time a token is valid is 60 minutes).
+ * This cache and expiry period is system-wide and does not attend to per-instance expiry time
+ * (e.g. "expires_in" from Google Compute -- which is set to the standard 3600 seconds).
+ */
+public class JWTBearerTokenFlow implements OAuthFilter {
+ private static final Joiner ON_COMMA = Joiner.on(",");
+
+ private final String audience;
+ private final Supplier<Credentials> credentialsSupplier;
+ private final OAuthScopes scopes;
+ private final long tokenDuration;
+ private final LoadingCache<Claims, Token> tokenCache;
+
+ public static class TestJWTBearerTokenFlow extends JWTBearerTokenFlow {
+
+ @Inject TestJWTBearerTokenFlow(AuthorizeToken loader, @Named(PROPERTY_SESSION_INTERVAL) long tokenDuration,
+ @Named(AUDIENCE) String audience, @Provider Supplier<Credentials> credentialsSupplier, OAuthScopes scopes) {
+ super(loader, tokenDuration, audience, credentialsSupplier, scopes);
+ }
+
+ /** Constant time for testing. */
+ long currentTimeSeconds() {
+ return 0;
+ }
+ }
+
+ @Inject JWTBearerTokenFlow(AuthorizeToken loader, @Named(PROPERTY_SESSION_INTERVAL) long tokenDuration,
+ @Named(AUDIENCE) String audience, @Provider Supplier<Credentials> credentialsSupplier, OAuthScopes scopes) {
+ this.audience = audience;
+ this.credentialsSupplier = credentialsSupplier;
+ this.scopes = scopes;
+ this.tokenDuration = tokenDuration;
+ // since the session interval is also the token expiration time requested to the server make the token expire a
+ // bit before the deadline to make sure there aren't session expiration exceptions
+ long cacheExpirationSeconds = tokenDuration > 30 ? tokenDuration - 30 : tokenDuration;
+ this.tokenCache = CacheBuilder.newBuilder().expireAfterWrite(tokenDuration, SECONDS).build(loader);
+ }
+
+ static final class AuthorizeToken extends CacheLoader<Claims, Token> {
+ private final AuthorizationApi api;
+
+ @Inject AuthorizeToken(AuthorizationApi api) {
+ this.api = api;
+ }
+
+ @Override public Token load(Claims key) throws Exception {
+ return api.authorize(key);
+ }
+ }
+
+ @Override public HttpRequest filter(HttpRequest request) throws HttpException {
+ long now = currentTimeSeconds();
+ Claims claims = Claims.create( //
+ credentialsSupplier.get().identity, // iss
+ ON_COMMA.join(scopes.forRequest(request)), // scope
+ audience, // aud
+ now + tokenDuration, // exp
+ now // iat
+ );
+ Token token = tokenCache.getUnchecked(claims);
+ String authorization = String.format("%s %s", token.tokenType(), token.accessToken());
+ return request.toBuilder().addHeader("Authorization", authorization).build();
+ }
+
+ long currentTimeSeconds() {
+ return System.currentTimeMillis() / 1000;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticationFilter.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticationFilter.java
deleted file mode 100644
index e6e5714..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticationFilter.java
+++ /dev/null
@@ -1,27 +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.filters;
-
-import org.jclouds.http.HttpRequestFilter;
-
-/**
- * Marker interface to specify auth mechanism (credentials or bearer token)
- *
- */
-public interface OAuthAuthenticationFilter extends HttpRequestFilter {
-
-}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java
----------------------------------------------------------------------
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
deleted file mode 100644
index cb858b5..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java
+++ /dev/null
@@ -1,51 +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.filters;
-
-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 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
- */
-public final class OAuthAuthenticator implements OAuthAuthenticationFilter {
-
- private Function<HttpRequest, TokenRequest> tokenRequestBuilder;
- private Function<TokenRequest, Token> tokenFetcher;
-
- @Inject OAuthAuthenticator(Function<HttpRequest, TokenRequest> tokenRequestBuilder,
- LoadingCache<TokenRequest, Token> tokenFetcher) {
- this.tokenRequestBuilder = tokenRequestBuilder;
- this.tokenFetcher = tokenFetcher;
- }
-
- @Override public HttpRequest filter(HttpRequest request) throws HttpException {
- TokenRequest tokenRequest = tokenRequestBuilder.apply(request);
- Token token = tokenFetcher.apply(tokenRequest);
- String authorization = String.format("%s %s", token.tokenType(), token.accessToken());
- return request.toBuilder().addHeader("Authorization", authorization).build();
- }
-}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthFilter.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthFilter.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthFilter.java
new file mode 100644
index 0000000..fa07d1e
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthFilter.java
@@ -0,0 +1,23 @@
+/*
+ * 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.filters;
+
+import org.jclouds.http.HttpRequestFilter;
+
+/** Indicates use of auth mechanism according to {@link org.jclouds.oauth.v2.config.OAuthProperties#CREDENTIAL_TYPE). */
+public interface OAuthFilter extends HttpRequestFilter {
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java
----------------------------------------------------------------------
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
deleted file mode 100644
index 51ab318..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java
+++ /dev/null
@@ -1,92 +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.functions;
-
-import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
-import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE;
-import static org.jclouds.oauth.v2.config.OAuthProperties.JWS_ALG;
-import static org.jclouds.oauth.v2.domain.Claims.EXPIRATION_TIME;
-import static org.jclouds.oauth.v2.domain.Claims.ISSUED_AT;
-
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-
-import org.jclouds.domain.Credentials;
-import org.jclouds.http.HttpRequest;
-import org.jclouds.location.Provider;
-import org.jclouds.oauth.v2.config.OAuthScopes;
-import org.jclouds.oauth.v2.domain.Header;
-import org.jclouds.oauth.v2.domain.TokenRequest;
-
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.base.Supplier;
-
-/** Builds the default token request with the following claims: {@code iss,scope,aud,iat,exp}. */
-public class BuildTokenRequest implements Function<HttpRequest, TokenRequest> {
- private static final Joiner ON_COMMA = Joiner.on(",");
-
- private final String assertionTargetDescription;
- private final String signatureAlgorithm;
- private final Supplier<Credentials> credentialsSupplier;
- private final OAuthScopes scopes;
- private final long tokenDuration;
-
- public static class TestBuildTokenRequest extends BuildTokenRequest {
- @Inject TestBuildTokenRequest(@Named(AUDIENCE) String assertionTargetDescription,
- @Named(JWS_ALG) String signatureAlgorithm, @Provider Supplier<Credentials> credentialsSupplier,
- OAuthScopes scopes, @Named(PROPERTY_SESSION_INTERVAL) long tokenDuration) {
- super(assertionTargetDescription, signatureAlgorithm, credentialsSupplier, scopes, tokenDuration);
- }
-
- public long currentTimeSeconds() {
- return 0;
- }
- }
-
- @Inject BuildTokenRequest(@Named(AUDIENCE) String assertionTargetDescription,
- @Named(JWS_ALG) String signatureAlgorithm, @Provider Supplier<Credentials> credentialsSupplier,
- OAuthScopes scopes, @Named(PROPERTY_SESSION_INTERVAL) long tokenDuration) {
- this.assertionTargetDescription = assertionTargetDescription;
- this.signatureAlgorithm = signatureAlgorithm;
- this.credentialsSupplier = credentialsSupplier;
- this.scopes = scopes;
- this.tokenDuration = tokenDuration;
- }
-
- @Override public TokenRequest apply(HttpRequest request) {
- Header header = Header.create(signatureAlgorithm, "JWT");
-
- Map<String, Object> claims = new LinkedHashMap<String, Object>();
- claims.put("iss", credentialsSupplier.get().identity);
- claims.put("scope", ON_COMMA.join(scopes.forRequest(request)));
- claims.put("aud", assertionTargetDescription);
-
- long now = currentTimeSeconds();
- claims.put(EXPIRATION_TIME, now + tokenDuration);
- claims.put(ISSUED_AT, now);
-
- return TokenRequest.create(header, claims);
- }
-
- long currentTimeSeconds() {
- return System.currentTimeMillis() / 1000;
- }
-}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/ClaimsToAssertion.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/ClaimsToAssertion.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/ClaimsToAssertion.java
new file mode 100644
index 0000000..d40f12e
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/ClaimsToAssertion.java
@@ -0,0 +1,87 @@
+/*
+ * 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.functions;
+
+import static com.google.common.base.Charsets.UTF_8;
+import static com.google.common.base.Joiner.on;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.io.BaseEncoding.base64Url;
+import static org.jclouds.oauth.v2.config.OAuthProperties.JWS_ALG;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.jclouds.json.Json;
+import org.jclouds.oauth.v2.config.Authorization;
+import org.jclouds.rest.AuthorizationException;
+
+import com.google.common.base.Function;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+
+public final class ClaimsToAssertion implements Function<Object, String> {
+ private static final List<String> SUPPORTED_ALGS = ImmutableList.of("RS256", "none");
+
+ private final Supplier<PrivateKey> privateKey;
+ private final Json json;
+ private final String alg;
+
+ @Inject ClaimsToAssertion(@Named(JWS_ALG) String alg, @Authorization Supplier<PrivateKey> privateKey, Json json) {
+ this.alg = alg;
+ checkArgument(SUPPORTED_ALGS.contains(alg), "%s %s not in supported list", JWS_ALG, alg, SUPPORTED_ALGS);
+ this.privateKey = privateKey;
+ this.json = json;
+ }
+
+ @Override public String apply(Object input) {
+ String encodedHeader = String.format("{\"alg\":\"%s\",\"typ\":\"JWT\"}", alg);
+ String encodedClaimSet = json.toJson(input);
+
+ encodedHeader = base64Url().omitPadding().encode(encodedHeader.getBytes(UTF_8));
+ encodedClaimSet = base64Url().omitPadding().encode(encodedClaimSet.getBytes(UTF_8));
+
+ byte[] signature = alg.equals("none")
+ ? null
+ : sha256(privateKey.get(), 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
+ return on(".").join(encodedHeader, encodedClaimSet, encodedSignature);
+ }
+
+ static byte[] sha256(PrivateKey privateKey, byte[] input) {
+ try {
+ Signature signature = Signature.getInstance("SHA256withRSA");
+ signature.initSign(privateKey);
+ signature.update(input);
+ return signature.sign();
+ } catch (NoSuchAlgorithmException e) {
+ throw new AssertionError(e);
+ } catch (SignatureException e) {
+ throw new AuthorizationException(e);
+ } catch (InvalidKeyException e) {
+ throw new AuthorizationException(e);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java
----------------------------------------------------------------------
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
deleted file mode 100644
index 1a02cab..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java
+++ /dev/null
@@ -1,38 +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.functions;
-
-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 com.google.common.base.Function;
-
-public final class FetchToken implements Function<TokenRequest, Token> {
-
- private final OAuthApi oAuthApi;
-
- @Inject FetchToken(OAuthApi oAuthApi) {
- this.oAuthApi = oAuthApi;
- }
-
- @Override public Token apply(TokenRequest input) {
- return this.oAuthApi.authenticate(input);
- }
-}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/PrivateKeySupplier.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/PrivateKeySupplier.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/PrivateKeySupplier.java
deleted file mode 100644
index cbdad5e..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/PrivateKeySupplier.java
+++ /dev/null
@@ -1,105 +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.functions;
-
-import static com.google.common.base.Charsets.UTF_8;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Throwables.propagate;
-import static org.jclouds.crypto.Pems.privateKeySpec;
-import static org.jclouds.oauth.v2.config.OAuthProperties.JWS_ALG;
-import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
-
-import java.io.IOException;
-import java.security.KeyFactory;
-import java.security.PrivateKey;
-import java.security.spec.InvalidKeySpecException;
-
-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.JWSAlgorithms;
-import org.jclouds.rest.AuthorizationException;
-
-import com.google.common.annotations.VisibleForTesting;
-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 PrivateKey} from a pem private key using the KeyFactory obtained vi {@link
- * JWSAlgorithms#keyFactory(String)}. The pem pk algorithm must match the KeyFactory algorithm.
- */
-@Singleton // due to cache
-public final class PrivateKeySupplier implements Supplier<PrivateKey> {
-
- private final Supplier<Credentials> creds;
- private final LoadingCache<Credentials, PrivateKey> keyCache;
-
- @Inject PrivateKeySupplier(@Provider Supplier<Credentials> creds, PrivateKeyForCredentials loader) {
- this.creds = creds;
- // throw out the private key related to old credentials
- this.keyCache = CacheBuilder.newBuilder().maximumSize(2).build(checkNotNull(loader, "loader"));
- }
-
- /**
- * it is relatively expensive to extract a private key from a PEM. cache the relationship between current
- * credentials
- * so that the private key is only recalculated once.
- */
- @VisibleForTesting
- static final class PrivateKeyForCredentials extends CacheLoader<Credentials, PrivateKey> {
- private final String jwsAlg;
-
- @Inject PrivateKeyForCredentials(@Named(JWS_ALG) String jwsAlg) {
- this.jwsAlg = jwsAlg;
- }
-
- @Override public PrivateKey load(Credentials in) {
- try {
- String privateKeyInPemFormat = in.credential;
- KeyFactory keyFactory = JWSAlgorithms.keyFactory(jwsAlg);
- return keyFactory.generatePrivate(privateKeySpec(ByteSource.wrap(privateKeyInPemFormat.getBytes(UTF_8))));
- } catch (IOException e) {
- throw propagate(e);
- } catch (InvalidKeySpecException e) {
- throw new AuthorizationException("security exception loading credentials. " + e.getMessage(), e);
- // catch IAE that is thrown when parsing the pk fails
- } catch (IllegalArgumentException e) {
- throw new AuthorizationException("cannot parse pk. " + e.getMessage(), e);
- }
- }
- }
-
- @Override public PrivateKey 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) {
- AuthorizationException authorizationException = getFirstThrowableOfType(e, AuthorizationException.class);
- if (authorizationException != null) {
- throw authorizationException;
- }
- throw e;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java
----------------------------------------------------------------------
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
deleted file mode 100644
index fd827b1..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java
+++ /dev/null
@@ -1,101 +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.functions;
-
-import static com.google.common.base.Throwables.propagate;
-import static org.jclouds.oauth.v2.JWSAlgorithms.macOrSignature;
-import static org.jclouds.oauth.v2.config.OAuthProperties.JWS_ALG;
-
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.Signature;
-import java.security.SignatureException;
-
-import javax.crypto.Mac;
-import javax.inject.Inject;
-import javax.inject.Named;
-
-import org.jclouds.oauth.v2.config.OAuth;
-import org.jclouds.rest.AuthorizationException;
-
-import com.google.common.base.Function;
-import com.google.common.base.Supplier;
-
-/**
- * Function that signs/produces mac's for OAuth tokens, provided a {@link Signature} or a {@link Mac} algorithm and
- * {@link PrivateKey}
- */
-public final class SignOrProduceMacForToken implements Supplier<Function<byte[], byte[]>> {
-
- private final String macOrSignature;
- private final Supplier<PrivateKey> credentials;
-
- @Inject SignOrProduceMacForToken(@Named(JWS_ALG) String jwsAlg, @OAuth Supplier<PrivateKey> credentials) {
- this.macOrSignature = macOrSignature(jwsAlg);
- this.credentials = credentials;
- }
-
- @Override public Function<byte[], byte[]> get() {
- try {
- if (macOrSignature.startsWith("SHA")) {
- return new SignatureGenerator(macOrSignature, credentials.get());
- }
- return new MessageAuthenticationCodeGenerator(macOrSignature, credentials.get());
- } catch (NoSuchAlgorithmException e) {
- throw new AssertionError("Invalid contents in JWSAlgorithms! " + e.getMessage());
- } catch (InvalidKeyException e) {
- throw new AuthorizationException("cannot parse pk. " + e.getMessage(), e);
- }
- }
-
- private static class MessageAuthenticationCodeGenerator implements Function<byte[], byte[]> {
-
- private final Mac mac;
-
- private MessageAuthenticationCodeGenerator(String macAlgorithm, PrivateKey privateKey) throws
- NoSuchAlgorithmException, InvalidKeyException {
- this.mac = Mac.getInstance(macAlgorithm);
- this.mac.init(privateKey);
- }
-
- @Override public byte[] apply(byte[] input) {
- this.mac.update(input);
- return this.mac.doFinal();
- }
- }
-
- private static class SignatureGenerator implements Function<byte[], byte[]> {
-
- private final Signature signature;
-
- private SignatureGenerator(String signatureAlgorithm, PrivateKey privateKey) throws NoSuchAlgorithmException,
- InvalidKeyException {
- this.signature = Signature.getInstance(signatureAlgorithm);
- this.signature.initSign(privateKey);
- }
-
- @Override public byte[] apply(byte[] input) {
- try {
- signature.update(input);
- return signature.sign();
- } catch (SignatureException e) {
- throw propagate(e);
- }
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java
----------------------------------------------------------------------
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
deleted file mode 100644
index ddc88a8..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java
+++ /dev/null
@@ -1,58 +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 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;
-import org.jclouds.http.HttpResponseException;
-import org.jclouds.rest.AuthorizationException;
-import org.jclouds.rest.ResourceNotFoundException;
-
-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;
-
- Exception exception = message != null ? new HttpResponseException(command, response, message)
- : new HttpResponseException(command, response);
- message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
- response.getStatusLine());
- Status status = Status.fromStatusCode(response.getStatusCode());
- switch (status) {
- case BAD_REQUEST:
- break;
- case UNAUTHORIZED:
- case FORBIDDEN:
- exception = new AuthorizationException(message, exception);
- break;
- case NOT_FOUND:
- if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
- exception = new ResourceNotFoundException(message, exception);
- }
- break;
- case CONFLICT:
- exception = new IllegalStateException(message, exception);
- break;
- }
- command.setException(exception);
- }
-}