From 4da1ba8ff5c3acecf61704b37003114427993da3 Mon Sep 17 00:00:00 2001 From: adriancole Date: Sun, 28 Apr 2013 21:54:40 -0700 Subject: [PATCH 01/33] organized google code into its own subdir --- apis/oauth/README | 22 ++ apis/oauth/pom.xml | 122 +++++++++++ .../java/org/jclouds/oauth/v2/OAuthApi.java | 66 ++++++ .../jclouds/oauth/v2/OAuthApiMetadata.java | 85 ++++++++ .../org/jclouds/oauth/v2/OAuthConstants.java | 78 +++++++ .../oauth/v2/config/Authentication.java | 38 ++++ .../v2/config/OAuthAuthenticationModule.java | 56 +++++ .../oauth/v2/config/OAuthHttpApiModule.java | 49 +++++ .../jclouds/oauth/v2/config/OAuthModule.java | 87 ++++++++ .../oauth/v2/config/OAuthProperties.java | 48 +++++ .../jclouds/oauth/v2/config/OAuthScopes.java | 45 ++++ .../org/jclouds/oauth/v2/domain/ClaimSet.java | 194 ++++++++++++++++++ .../org/jclouds/oauth/v2/domain/Header.java | 131 ++++++++++++ .../oauth/v2/domain/OAuthCredentials.java | 131 ++++++++++++ .../org/jclouds/oauth/v2/domain/Token.java | 153 ++++++++++++++ .../jclouds/oauth/v2/domain/TokenRequest.java | 135 ++++++++++++ .../oauth/v2/domain/TokenRequestFormat.java | 49 +++++ .../oauth/v2/filters/OAuthAuthenticator.java | 67 ++++++ .../oauth/v2/functions/BuildTokenRequest.java | 136 ++++++++++++ .../oauth/v2/functions/FetchToken.java | 47 +++++ .../functions/OAuthCredentialsSupplier.java | 127 ++++++++++++ .../functions/SignOrProduceMacForToken.java | 123 +++++++++++ .../oauth/v2/handlers/OAuthErrorHandler.java | 68 ++++++ .../oauth/v2/handlers/OAuthTokenBinder.java | 49 +++++ .../oauth/v2/json/ClaimSetTypeAdapter.java | 63 ++++++ .../oauth/v2/json/HeaderTypeAdapter.java | 54 +++++ .../oauth/v2/json/JWTTokenRequestFormat.java | 100 +++++++++ .../services/org.jclouds.apis.ApiMetadata | 1 + .../oauth/v2/OAuthApiMetadataTest.java | 42 ++++ .../org/jclouds/oauth/v2/OAuthTestUtils.java | 81 ++++++++ .../oauth/v2/features/OAuthApiExpectTest.java | 103 ++++++++++ .../oauth/v2/features/OAuthApiLiveTest.java | 85 ++++++++ .../functions/OAuthCredentialsFromPKTest.java | 60 ++++++ .../OAuthCredentialsSupplierTest.java | 61 ++++++ .../v2/functions/SignerFunctionTest.java | 65 ++++++ .../v2/handlers/OAuthErrorHandlerTest.java | 97 +++++++++ .../oauth/v2/internal/Base64UrlSafeTest.java | 45 ++++ .../v2/internal/BaseOAuthApiExpectTest.java | 28 +++ .../v2/internal/BaseOAuthApiLiveTest.java | 63 ++++++ .../BaseOAuthAuthenticatedApiLiveTest.java | 116 +++++++++++ .../v2/internal/BaseOAuthExpectTest.java | 31 +++ .../v2/json/JWTTokenRequestFormatTest.java | 75 +++++++ .../oauth/v2/parse/ParseTokenTest.java | 46 +++++ apis/oauth/src/test/resources/logback.xml | 38 ++++ apis/oauth/src/test/resources/testpk.pem | 15 ++ .../src/test/resources/tokenResponse.json | 5 + 46 files changed, 3380 insertions(+) create mode 100644 apis/oauth/README create mode 100644 apis/oauth/pom.xml create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApi.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authentication.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthAuthenticationModule.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthHttpApiModule.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthModule.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Header.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequest.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequestFormat.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthTokenBinder.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/json/HeaderTypeAdapter.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java create mode 100644 apis/oauth/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata create mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java create mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java create mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiExpectTest.java create mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java create mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java create mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java create mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/SignerFunctionTest.java create mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java create mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/Base64UrlSafeTest.java create mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiExpectTest.java create mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java create mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java create mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthExpectTest.java create mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormatTest.java create mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java create mode 100644 apis/oauth/src/test/resources/logback.xml create mode 100644 apis/oauth/src/test/resources/testpk.pem create mode 100644 apis/oauth/src/test/resources/tokenResponse.json diff --git a/apis/oauth/README b/apis/oauth/README new file mode 100644 index 0000000000..32b571a421 --- /dev/null +++ b/apis/oauth/README @@ -0,0 +1,22 @@ +In order to use oauth applications must specify the following properties: + +Mandatory: +.identity - the oauth identity (e.g., service account email in Google Api's) +.credential - the private key used to sign requests, in pem format +oauth.endpoint - the endpoint to use for authentication (e.g., "http://accounts.google.com/o/oauth2/token" in Google Api's) +oauth.audience - the "audience" of the token request (e.g., "http://accounts.google.com/o/oauth2/token" in Google Api's) + +Optional: +- each application may expose a Map of additional claims to be added to the token request, +these should be annotated/named with "oauth.additional-claims" +oauth.signature-or-mac-algorithm - the algorithms to use when signing the token request. + +Running the live test: + +mvn clean install -Plive\ + -Dtest.oauth.identity=\ + -Dtest.oauth.credential=\ + -Dtest.oauth.endpoint=https://accounts.google.com/o/oauth2/token\ + -Dtest.jclouds.oauth.audience=https://accounts.google.com/o/oauth2/token\ + -Dtest.jclouds.oauth.signature-or-mac-algorithm=RS256\ + -Dtest.jclouds.oauth.scopes=https://www.googleapis.com/auth/prediction \ No newline at end of file diff --git a/apis/oauth/pom.xml b/apis/oauth/pom.xml new file mode 100644 index 0000000000..aa2cb253c5 --- /dev/null +++ b/apis/oauth/pom.xml @@ -0,0 +1,122 @@ + + + + 4.0.0 + + org.jclouds.labs + jclouds-labs-google + 1.7.0-SNAPSHOT + + + + org.jclouds.labs + oauth + jclouds OAuth core + jclouds components to access OAuth + + + FIX_ME + FIX_ME + FIX_ME + FIX_ME + FIX_ME + FIX_ME + 2 + + + + + + org.jclouds + jclouds-core + ${jclouds.version} + + + org.jclouds + jclouds-core + ${jclouds.version} + test-jar + test + + + org.jclouds.driver + jclouds-slf4j + ${jclouds.version} + test + + + ch.qos.logback + logback-classic + test + + + + + + + maven-jar-plugin + + + + test-jar + + + + + + + + + + live + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration + integration-test + + test + + + + ${test.oauth.identity} + ${test.oauth.credential} + ${test.oauth.endpoint} + ${test.oauth.api-version} + ${test.oauth.build-version} + ${test.jclouds.oauth.signature-or-mac-algorithm>} + ${test.jclouds.oauth.audience} + ${test.jclouds.oauth.scopes} + + + + + + + + + + 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 new file mode 100644 index 0000000000..2725778165 --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApi.java @@ -0,0 +1,66 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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 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.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; + +/** + * Provides access to OAuth via REST api. + *

+ * 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. + * + * @author David Alves + * @see OAuthAsyncApi + */ +@Endpoint(Authentication.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(MediaType.APPLICATION_JSON) + Token authenticate(@BinderParam(OAuthTokenBinder.class) TokenRequest tokenRequest) throws AuthorizationException; + +} 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 new file mode 100644 index 0000000000..a093d699b8 --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java @@ -0,0 +1,85 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; + +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.common.collect.ImmutableSet; +import com.google.inject.Module; + +/** + * Implementation of {@link ApiMetadata} for OAuth 2 API + * + * @author David Alves + */ +public class OAuthApiMetadata extends BaseHttpApiMetadata { + + @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(SIGNATURE_OR_MAC_ALGORITHM, "RS256"); + properties.put(PROPERTY_SESSION_INTERVAL, 3600); + return properties; + } + + public static class Builder extends BaseHttpApiMetadata.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.>of(OAuthModule.class, OAuthHttpApiModule.class)); + } + + @Override + public OAuthApiMetadata build() { + return new OAuthApiMetadata(this); + } + + @Override + protected Builder self() { + return this; + } + } +} diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java new file mode 100644 index 0000000000..59fc43031c --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java @@ -0,0 +1,78 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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 com.google.common.collect.ImmutableMap; + +import java.util.Map; + +/** + * The constants for OAuth \ + * + * @author David Alves + */ +public class OAuthConstants { + + /** + * Selected algorithm when a signature or mac isn't required. + */ + public static final String NO_ALGORITHM = "none"; + + /** + * Static mapping between the oauth algorithm name and the Crypto provider signature algorithm name. + * + * @see doc + * @see org.jclouds.oauth.v2.json.JWTTokenRequestFormat + */ + public static final Map OAUTH_ALGORITHM_NAMES_TO_SIGNATURE_ALGORITHM_NAMES = ImmutableMap + .builder() + .put("RS256", "SHA256withRSA") + .put("RS384", "SHA384withRSA") + .put("RS512", "SHA512withRSA") + .put("HS256", "HmacSHA256") + .put("HS384", "HmacSHA384") + .put("HS512", "HmacSHA512") + .put("ES256", "SHA256withECDSA") + .put("ES384", "SHA384withECDSA") + .put("ES512", "SHA512withECDSA") + .put(NO_ALGORITHM, NO_ALGORITHM).build(); + + /** + * Static mapping between the oauth algorithm name and the Crypto provider KeyFactory algorithm name. + * + * @see doc + */ + public static final Map OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES = ImmutableMap + .builder() + .put("RS256", "RSA") + .put("RS384", "RSA") + .put("RS512", "RSA") + .put("HS256", "DiffieHellman") + .put("HS384", "DiffieHellman") + .put("HS512", "DiffieHellman") + .put("ES256", "EC") + .put("ES384", "EC") + .put("ES512", "EC") + .put(NO_ALGORITHM, NO_ALGORITHM).build(); + + /** + * The (optional) set of additional claims to use, provided in Map form + */ + public static final String ADDITIONAL_CLAIMS = "jclouds.oauth.additional-claims"; +} diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authentication.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authentication.java new file mode 100644 index 0000000000..b0b301d435 --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authentication.java @@ -0,0 +1,38 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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 javax.inject.Qualifier; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Qualifies OAuth related resources, such as Endpoint. + * + * @author David Alves + * @see org.jclouds.oauth.v2.OAuthAsyncApi + */ +@Retention(value = RetentionPolicy.RUNTIME) +@Target(value = {ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD}) +@Qualifier +public @interface Authentication { +} 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 new file mode 100644 index 0000000000..24a5d41652 --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthAuthenticationModule.java @@ -0,0 +1,56 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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; + +/** + * An OAuth module to be used form other providers. + * + * @author David Alves + */ +public class OAuthAuthenticationModule extends AbstractModule { + + @Override + protected void configure() { + bindHttpApi(binder(), OAuthApi.class); + } + + /** + * When oauth is used as a module the oauth endpoint is a normal property + */ + @Provides + @Singleton + @Authentication + protected Supplier provideAuthenticationEndpoint(@Named("oauth.endpoint") String endpoint) { + return Suppliers.ofInstance(URI.create(endpoint)); + } +} 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 new file mode 100644 index 0000000000..9234242ff5 --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthHttpApiModule.java @@ -0,0 +1,49 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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; + +/** + * OAuth module to when accessing OAuth stand-alone. + * + * @author David Alves + */ +@ConfiguresHttpApi +public class OAuthHttpApiModule extends HttpApiModule { + + @Provides + @Singleton + @Authentication + protected Supplier provideAuthenticationEndpoint(ProviderMetadata providerMetadata) { + return Suppliers.ofInstance(URI.create(providerMetadata.getEndpoint())); + } + +} 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 new file mode 100644 index 0000000000..fc55a87da8 --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthModule.java @@ -0,0 +1,87 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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 com.google.common.base.Function; +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.collect.ImmutableMap; +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.TypeLiteral; +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.Token; +import org.jclouds.oauth.v2.domain.TokenRequest; +import org.jclouds.oauth.v2.functions.BuildTokenRequest; +import org.jclouds.oauth.v2.functions.FetchToken; +import org.jclouds.oauth.v2.functions.OAuthCredentialsSupplier; +import org.jclouds.oauth.v2.functions.SignOrProduceMacForToken; +import org.jclouds.oauth.v2.json.ClaimSetTypeAdapter; +import org.jclouds.oauth.v2.json.HeaderTypeAdapter; +import org.jclouds.rest.internal.GeneratedHttpRequest; + +import javax.inject.Named; +import javax.inject.Singleton; +import java.lang.reflect.Type; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; + +/** + * Base OAuth module + * + * @author David Alves + */ +public class OAuthModule extends AbstractModule { + + + @Override + protected void configure() { + bind(new TypeLiteral>() {}).to(SignOrProduceMacForToken.class); + bind(new TypeLiteral>() {}).toInstance(ImmutableMap.of( + Header.class, new HeaderTypeAdapter(), + ClaimSet.class, new ClaimSetTypeAdapter())); + bind(new TypeLiteral>() {}).to(OAuthCredentialsSupplier.class); + bind(new TypeLiteral>() {}).to(BuildTokenRequest.class); + bind(new TypeLiteral>() {}).to(FetchToken.class); + } + + /** + * Provides a cache for tokens. Cache is time based and expires after 59 minutes (the maximum time a token is + * valid is 60 minutes) + */ + @Provides + @Singleton + public LoadingCache provideAccessCache(Function getAccess, + @Named(PROPERTY_SESSION_INTERVAL) long + sessionIntervalInSeconds) { + // 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 + sessionIntervalInSeconds = sessionIntervalInSeconds > 30 ? sessionIntervalInSeconds - 30 : + sessionIntervalInSeconds; + return CacheBuilder.newBuilder().expireAfterWrite(sessionIntervalInSeconds, TimeUnit.MINUTES).build(CacheLoader + .from(getAccess)); + } + +} 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 new file mode 100644 index 0000000000..60fb13d726 --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java @@ -0,0 +1,48 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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; + +/** + * Configurable properties for jclouds OAuth + * + * @author David Alves + */ +public class OAuthProperties { + + /** + * The selected signature algorithm to use to sign the requests. + *

+ * This refers to the name the oauth provider expects, i.e., "RSA + */ + public static final String SIGNATURE_OR_MAC_ALGORITHM = "jclouds.oauth.signature-or-mac-algorithm"; + + /** + * 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 doc + */ + public static final String AUDIENCE = "jclouds.oauth.audience"; + + /** + * Optional list of comma-separated scopes to use when no OAuthScopes annotation is present. + */ + public static final String SCOPES = "jclouds.oauth.scopes"; +} diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java new file mode 100644 index 0000000000..f1136fe33b --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java @@ -0,0 +1,45 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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 javax.inject.Qualifier; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Used to annotate REST methods/ifaces that use OAuthAuthentication. + *

+ * Sets the scopes for the token request for that particular method. + * + * @author David Alves + */ +@Retention(value = RetentionPolicy.RUNTIME) +@Target(value = {ElementType.TYPE, ElementType.METHOD}) +@Qualifier +public @interface OAuthScopes { + + /** + * @return the OAuth scopes required to access the resource. + */ + String[] value(); + +} diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java new file mode 100644 index 0000000000..998ddcb08b --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java @@ -0,0 +1,194 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.common.base.Objects; +import com.google.common.base.Splitter; +import com.google.common.collect.ForwardingMap; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; + +import java.util.Map; +import java.util.Set; + +import static com.google.common.base.Objects.ToStringHelper; +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +/** + * The claimset for the token. + * + * @author David Alves + * @see doc + */ +public class ClaimSet extends ForwardingMap { + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromClaimSet(this); + } + + public static class Builder { + + private Set requiredClaims; + private ImmutableMap.Builder claims = new ImmutableMap.Builder(); + private long emissionTime; + private long expirationTime; + + public Builder() { + this(ImmutableSet.of()); + } + + /** + * Constructor that allows to predefine a mandatory set of claims as a comma-separated string, e.g, "iss,iat". + */ + public Builder(String commaSeparatedRequiredClaims) { + this(ImmutableSet.copyOf(Splitter.on(",").split(checkNotNull(commaSeparatedRequiredClaims)))); + } + + /** + * Constructor that allows to predefine a mandatory set of claims as a set of strings. + */ + public Builder(Set requiredClaims) { + this.requiredClaims = ImmutableSet.copyOf(checkNotNull(requiredClaims)); + } + + /** + * Adds a Claim, i.e. key/value pair, e.g., "scope":"all_permissions". + */ + public Builder addClaim(String name, String value) { + claims.put(checkNotNull(name), checkNotNull(value, "value of %s", name)); + return this; + } + + /** + * @see ClaimSet#getEmissionTime() + */ + public Builder emissionTime(long emmissionTime) { + this.emissionTime = emmissionTime; + return this; + } + + /** + * @see ClaimSet#getExpirationTime() + */ + public Builder expirationTime(long expirationTime) { + this.expirationTime = expirationTime; + return this; + } + + /** + * Adds a map containing multiple claims + */ + public Builder addAllClaims(Map claims) { + this.claims.putAll(checkNotNull(claims)); + return this; + } + + public ClaimSet build() { + Map claimsMap = claims.build(); + checkState(Sets.intersection(claimsMap.keySet(), requiredClaims).size() == requiredClaims.size(), + "not all required claims were present"); + if (expirationTime == 0) { + expirationTime = emissionTime + 3600; + } + return new ClaimSet(claimsMap, emissionTime, expirationTime); + } + + public Builder fromClaimSet(ClaimSet claimSet) { + return new Builder().addAllClaims(claimSet.claims).expirationTime(expirationTime).emissionTime(emissionTime); + } + } + + private final Map claims; + private final long emissionTime; + private final long expirationTime; + + private ClaimSet(Map claims, long emissionTime, long expirationTime) { + this.claims = claims; + this.emissionTime = emissionTime; + this.expirationTime = expirationTime; + } + + /** + * The emission time, in seconds since the epoch. + */ + public long getEmissionTime() { + return emissionTime; + } + + /** + * The expiration time, in seconds since the emission time. + */ + public long getExpirationTime() { + return expirationTime; + } + + /** + * @returns the claims. + */ + @Override + protected Map delegate() { + return claims; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(claims); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ClaimSet other = (ClaimSet) obj; + return equal(claims, other.claims); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + protected ToStringHelper string() { + return toStringHelper(this).omitNullValues().add("claims", claims) + .add("emissionTime", emissionTime).add("expirationTIme", expirationTime); + } +} 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 new file mode 100644 index 0000000000..ab4cd640a0 --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Header.java @@ -0,0 +1,131 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.common.base.Objects; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * The header for the OAuth token, contains the signer algorithm's name and the type of the token + * + * @author David Alves + * @see doc + */ +public class Header { + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromHeader(this); + } + + public static class Builder { + + private String signerAlgorithm; + private String type; + + /** + * @see Header#getSignerAlgorithm() + */ + public Builder signerAlgorithm(String signerAlgorithm) { + this.signerAlgorithm = checkNotNull(signerAlgorithm); + return this; + } + + /** + * @see Header#getType() + */ + public Builder type(String type) { + this.type = checkNotNull(type); + return this; + } + + public Header build() { + return new Header(signerAlgorithm, type); + } + + public Builder fromHeader(Header header) { + return new Builder().signerAlgorithm(header.signerAlgorithm).type(header.type); + } + } + + private final String signerAlgorithm; + private final String type; + + protected Header(String signerAlgorithm, String type) { + this.signerAlgorithm = checkNotNull(signerAlgorithm); + this.type = checkNotNull(type); + } + + /** + * The name of the algorithm used to compute the signature, e.g., "RS256" + */ + public String getSignerAlgorithm() { + return signerAlgorithm; + } + + /** + * The type of the token, e.g., "JWT" + */ + public String getType() { + return type; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Header other = (Header) obj; + return equal(this.signerAlgorithm, other.signerAlgorithm) && equal(this.type, + other.type); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(signerAlgorithm, type); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + protected Objects.ToStringHelper string() { + return toStringHelper(this).omitNullValues().add("signerAlgorithm", signerAlgorithm) + .add("type", type); + } +} diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java new file mode 100644 index 0000000000..bd2ee25fcb --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java @@ -0,0 +1,131 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.common.base.Objects; +import org.jclouds.domain.Credentials; + +import java.security.PrivateKey; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Special kind credentials for oauth authentication that includes {@link java.security.PrivateKey} to sign + * requests. + */ +public class OAuthCredentials extends Credentials { + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromOauthCredentials(this); + } + + public static class Builder extends Credentials.Builder { + + protected PrivateKey privateKey; + + /** + * @see OAuthCredentials#privateKey + */ + public Builder privateKey(PrivateKey privateKey) { + this.privateKey = checkNotNull(privateKey); + return this; + } + + /** + * @see Credentials#identity + */ + public Builder identity(String identity) { + this.identity = checkNotNull(identity); + return this; + } + + /** + * @see Credentials#credential + */ + public Builder credential(String credential) { + this.credential = credential; + return this; + } + + public OAuthCredentials build() { + return new OAuthCredentials(checkNotNull(identity), credential, privateKey); + } + + public Builder fromOauthCredentials(OAuthCredentials credentials) { + return new Builder().privateKey(credentials.privateKey).identity(credentials.identity) + .credential(credentials.credential); + } + } + + /** + * The private key associated with Credentials#identity. + * Used to sign token requests. + */ + public final PrivateKey privateKey; + + public OAuthCredentials(String identity, String credential, PrivateKey privateKey) { + super(identity, credential); + this.privateKey = privateKey; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + OAuthCredentials other = (OAuthCredentials) obj; + return equal(this.identity, other.identity) && equal(this.credential, + other.credential) && equal(this.privateKey, + other.privateKey); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(identity, credential, privateKey); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + protected Objects.ToStringHelper string() { + return toStringHelper(this).omitNullValues().add("identity", identity) + .add("credential", credential != null ? credential.hashCode() : null).add("privateKey", + privateKey.hashCode()); + } +} diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java new file mode 100644 index 0000000000..6ad47ea315 --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java @@ -0,0 +1,153 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.common.base.Objects; + +import java.beans.ConstructorProperties; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * The oauth token, obtained upon a successful token request and ready to embed in requests. + * + * @author David Alves + */ +public class Token { + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromToken(this); + } + + public static class Builder { + + private String accessToken; + private String tokenType; + private long expiresIn; + + /** + * @see Token#getAccessToken() + */ + public Builder accessToken(String accessToken) { + this.accessToken = checkNotNull(accessToken); + return this; + } + + /** + * @see Token#getTokenType() + */ + public Builder tokenType(String tokenType) { + this.tokenType = checkNotNull(tokenType); + return this; + } + + /** + * @see Token#getExpiresIn() + */ + public Builder expiresIn(long expiresIn) { + this.expiresIn = expiresIn; + return this; + } + + public Token build() { + return new Token(accessToken, tokenType, expiresIn); + } + + public Builder fromToken(Token token) { + return new Builder().accessToken(token.accessToken).tokenType(token.tokenType).expiresIn(token.expiresIn); + } + } + + private final String accessToken; + private final String tokenType; + private final long expiresIn; + + @ConstructorProperties({"access_token", "token_type", "expires_in"}) + protected Token(String accessToken, String tokenType, long expiresIn) { + this.accessToken = accessToken; + this.tokenType = tokenType; + this.expiresIn = expiresIn; + } + + /** + * The access token obtained from the OAuth server. + */ + public String getAccessToken() { + return accessToken; + } + + /** + * The type of the token, e.g., "Bearer" + */ + public String getTokenType() { + return tokenType; + } + + /** + * In how many seconds this token expires. + */ + public long getExpiresIn() { + return expiresIn; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Token other = (Token) obj; + return equal(this.accessToken, other.accessToken) && equal(this.tokenType, + other.tokenType) && equal(this.expiresIn, + other.expiresIn); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(accessToken, tokenType, expiresIn); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + protected Objects.ToStringHelper string() { + return toStringHelper(this).omitNullValues().add("accessToken", accessToken) + .add("tokenType", tokenType).add("expiresIn", expiresIn); + } + +} 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 new file mode 100644 index 0000000000..d2e6ab5bed --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequest.java @@ -0,0 +1,135 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.common.base.Objects; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A complete token request. + * + * @author David Alves + */ +public class TokenRequest { + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromTokenRequest(this); + } + + public static class Builder { + private Header header; + private ClaimSet claimSet; + + /** + * @see TokenRequest#getClaimSet() + */ + public Builder header(Header header) { + this.header = header; + return this; + } + + /** + * @see TokenRequest#getHeader() + */ + public Builder claimSet(ClaimSet claimSet) { + this.claimSet = claimSet; + return this; + } + + public TokenRequest build() { + return new TokenRequest(header, claimSet); + } + + public Builder fromTokenRequest(TokenRequest tokeRequest) { + return new Builder().header(tokeRequest.header).claimSet(tokeRequest.claimSet); + } + } + + private final Header header; + private final ClaimSet claimSet; + + public TokenRequest(Header header, ClaimSet claimSet) { + this.header = checkNotNull(header); + this.claimSet = checkNotNull(claimSet); + } + + /** + * The header of this token request. + * + * @see Header + */ + public Header getHeader() { + return header; + } + + /** + * The claim set of this token request. + * + * @see ClaimSet + */ + public ClaimSet getClaimSet() { + return claimSet; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TokenRequest other = (TokenRequest) obj; + return equal(this.header, other.header) && equal(this.claimSet, + other.claimSet); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(header, claimSet); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + protected Objects.ToStringHelper string() { + return toStringHelper(this).omitNullValues().add("header", header) + .add("claimSet", claimSet); + } + + +} 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 new file mode 100644 index 0000000000..7d4ab63fc6 --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequestFormat.java @@ -0,0 +1,49 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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) + * + * @author David Alves + */ +@ImplementedBy(JWTTokenRequestFormat.class) +public interface TokenRequestFormat { + + /** + * Transforms the provided HttpRequest into a particular token request with a specific format. + */ + public R formatRequest(R httpRequest, TokenRequest tokenRequest); + + /** + * The name of the type of the token request, e.g., "JWT" + */ + public String getTypeName(); + + /** + * The claims that must be present in the token request for it to be valid. + */ + public Set requiredClaims(); +} 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 new file mode 100644 index 0000000000..ccfd2a5ad4 --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java @@ -0,0 +1,67 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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 com.google.common.base.Function; +import com.google.common.cache.LoadingCache; +import org.jclouds.http.HttpException; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpRequestFilter; +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; + +/** + * 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 + * + * @author David Alves + */ +@Singleton +public class OAuthAuthenticator implements HttpRequestFilter { + + private Function tokenRequestBuilder; + private Function tokenFetcher; + + @Inject + OAuthAuthenticator(Function tokenRequestBuilder, LoadingCache tokenFetcher) { + this.tokenRequestBuilder = tokenRequestBuilder; + this.tokenFetcher = tokenFetcher; + } + + @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.getTokenType(), token.getAccessToken())).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 new file mode 100644 index 0000000000..8faa22d342 --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java @@ -0,0 +1,136 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.Preconditions.checkState; +import static org.jclouds.oauth.v2.OAuthConstants.ADDITIONAL_CLAIMS; +import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; +import static org.jclouds.oauth.v2.config.OAuthProperties.SCOPES; +import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; + +import java.util.Map; +import java.util.concurrent.TimeUnit; + +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.base.Ticker; +import com.google.common.collect.ImmutableMap; +import com.google.common.reflect.Invokable; +import com.google.inject.Inject; +import com.google.inject.name.Named; + +/** + * The default authenticator. + *

+ * Builds the default token request with the following claims: iss,scope,aud,iat,exp. + *

+ * TODO scopes etc should come from the REST method and not from a global property + * + * @author David Alves + */ +@Singleton +public class BuildTokenRequest implements Function { + + 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 = ImmutableMap.of(); + + @Inject(optional = true) + @Named(SCOPES) + protected String globalScopes = null; + + @Inject(optional = true) + public Ticker ticker = Ticker.systemTicker(); + + + @Inject + public BuildTokenRequest(@Named(AUDIENCE) String assertionTargetDescription, + @Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureAlgorithm, + TokenRequestFormat tokenRequestFormat, 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) { + long now = TimeUnit.SECONDS.convert(ticker.read(), TimeUnit.NANOSECONDS); + + // fetch the token + Header header = new Header.Builder() + .signerAlgorithm(signatureAlgorithm) + .type(tokenRequestFormat.getTypeName()) + .build(); + + ClaimSet claimSet = new ClaimSet.Builder(this.tokenRequestFormat.requiredClaims()) + .addClaim("iss", credentialsSupplier.get().identity) + .addClaim("scope", getOAuthScopes(request)) + .addClaim("aud", assertionTargetDescription) + .emissionTime(now) + .expirationTime(now + tokenDuration) + .addAllClaims(additionalClaims) + .build(); + + return new TokenRequest.Builder() + .header(header) + .claimSet(claimSet) + .build(); + } + + protected String getOAuthScopes(GeneratedHttpRequest request) { + Invokable invokable = request.getInvocation().getInvokable(); + + OAuthScopes classScopes = invokable.getOwnerType().getRawType().getAnnotation(OAuthScopes.class); + OAuthScopes methodScopes = invokable.getAnnotation(OAuthScopes.class); + + // if no annotations are present the rely on globally set scopes + if (classScopes == null && methodScopes == null) { + checkState(globalScopes != null, String.format("REST class or method should be annotated " + + "with OAuthScopes specifying required permissions. Alternatively a global property " + + "\"oauth.scopes\" may be set to define scopes globally. REST Class: %s, Method: %s", + invokable.getOwnerType(), + invokable.getName())); + return globalScopes; + } + + OAuthScopes scopes = methodScopes != null ? methodScopes : classScopes; + return Joiner.on(",").join(scopes.value()); + } +} 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 new file mode 100644 index 0000000000..a7975d92e4 --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java @@ -0,0 +1,47 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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 com.google.common.base.Function; +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; + +/** + * @author David Alves + */ +@Singleton +public class FetchToken implements Function { + + private OAuthApi oAuthApi; + + @Inject + public FetchToken(OAuthApi oAuthApi) { + this.oAuthApi = oAuthApi; + } + + @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 new file mode 100644 index 0000000000..d74bed52fe --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java @@ -0,0 +1,127 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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 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.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; +import static java.lang.String.format; +import static org.jclouds.crypto.Pems.privateKeySpec; +import static org.jclouds.io.Payloads.newStringPayload; +import static org.jclouds.oauth.v2.OAuthConstants.NO_ALGORITHM; +import static org.jclouds.oauth.v2.OAuthConstants.OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES; +import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; +import static org.jclouds.util.Throwables2.getFirstThrowableOfType; + +/** + * 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. + * + * @author David Alves + * @see org.jclouds.oauth.v2.OAuthConstants#OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES + */ +@Singleton +public class OAuthCredentialsSupplier implements Supplier { + + private final Supplier creds; + private final LoadingCache keyCache; + + @Inject + public 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), + format("No mapping for key factory for algorithm: %s", signatureOrMacAlgorithm)); + // 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 class OAuthCredentialsForCredentials extends CacheLoader { + private final String keyFactoryAlgorithm; + + @Inject + public 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) { + try { + String identity = in.identity; + String privateKeyInPemFormat = in.credential; + if (keyFactoryAlgorithm.equals(NO_ALGORITHM)) { + return new OAuthCredentials.Builder().identity(identity).credential(privateKeyInPemFormat).build(); + } + KeyFactory keyFactory = KeyFactory.getInstance(keyFactoryAlgorithm); + PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec(newStringPayload(privateKeyInPemFormat))); + return new OAuthCredentials.Builder().identity(identity).credential(privateKeyInPemFormat) + .privateKey(privateKey).build(); + } catch (IOException e) { + throw propagate(e); + // catch security exceptions InvalidKeySpecException and NoSuchAlgorithmException as GSE + } catch (GeneralSecurityException 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 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); + if (authorizationException != null) { + throw ((AuthorizationException) authorizationException); + } + throw propagate(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 new file mode 100644 index 0000000000..0d590a836e --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java @@ -0,0 +1,123 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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 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 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; + +/** + * Function that signs/produces mac's for OAuth tokens, provided a {@link Signature} or a {@link Mac} algorithm and + * {@link PrivateKey} + * + * @author David Alves + */ +public 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, + Supplier credentials) { + checkState(OAUTH_ALGORITHM_NAMES_TO_SIGNATURE_ALGORITHM_NAMES.containsKey(signatureOrMacAlgorithm), + format("the signature algorithm %s is not supported", signatureOrMacAlgorithm)); + this.signatureOrMacAlgorithm = OAUTH_ALGORITHM_NAMES_TO_SIGNATURE_ALGORITHM_NAMES.get(signatureOrMacAlgorithm); + this.credentials = credentials; + } + + @PostConstruct + public void loadSignatureOrMacOrNone() throws InvalidKeyException, NoSuchAlgorithmException { + if (signatureOrMacAlgorithm.equals(NO_ALGORITHM)) { + this.signatureOrMacFunction = new Function() { + @Override + public byte[] apply(byte[] input) { + return null; + } + }; + } else if (signatureOrMacAlgorithm.startsWith("SHA")) { + this.signatureOrMacFunction = new SignatureGenerator(signatureOrMacAlgorithm, credentials.get().privateKey); + } else { + this.signatureOrMacFunction = new MessageAuthenticationCodeGenerator(signatureOrMacAlgorithm, + credentials.get().privateKey); + } + } + + @Override + public byte[] apply(byte[] input) { + return signatureOrMacFunction.apply(input); + } + + private static class MessageAuthenticationCodeGenerator implements Function { + + private 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 { + + private 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 Throwables.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 new file mode 100644 index 0000000000..f83c83373a --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java @@ -0,0 +1,68 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.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; + +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. + * + * @author David Alves + */ +@Singleton +public class OAuthErrorHandler implements HttpErrorHandler { + 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); + } +} 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 new file mode 100644 index 0000000000..10ba408684 --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthTokenBinder.java @@ -0,0 +1,49 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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. + * + * @author David Alves + */ +@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/json/ClaimSetTypeAdapter.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java new file mode 100644 index 0000000000..b41a6b5030 --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java @@ -0,0 +1,63 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.oauth.v2.json; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import org.jclouds.oauth.v2.domain.ClaimSet; + +import java.io.IOException; +import java.util.Map; + +/** + * JSON TypeAdapter for the ClaimSet type. Pull the claims maps to the root level and adds two properties for the + * expiration time and issuing time. + * + * @author David Alves + */ +public class ClaimSetTypeAdapter extends TypeAdapter { + + @Override + public void write(JsonWriter out, ClaimSet value) throws IOException { + out.beginObject(); + for (Map.Entry entry : value.entrySet()) { + out.name(entry.getKey()); + out.value(entry.getValue()); + } + out.name("exp"); + out.value(value.getExpirationTime()); + out.name("iat"); + out.value(value.getEmissionTime()); + out.endObject(); + } + + @Override + public ClaimSet read(JsonReader in) throws IOException { + ClaimSet.Builder builder = new ClaimSet.Builder(); + in.beginObject(); + while (in.hasNext()) { + String claimName = in.nextName(); + String claimValue = in.nextString(); + builder.addClaim(claimName, claimValue); + } + in.endObject(); + return builder.build(); + } +} diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/HeaderTypeAdapter.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/HeaderTypeAdapter.java new file mode 100644 index 0000000000..a23d0c9cbd --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/HeaderTypeAdapter.java @@ -0,0 +1,54 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.oauth.v2.json; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import org.jclouds.oauth.v2.domain.Header; + +import java.io.IOException; + +/** + * JSON TypeAdapter for the Header type. Simply transforms the field names. + */ +public class HeaderTypeAdapter extends TypeAdapter

{ + + @Override + public void write(JsonWriter out, Header value) throws IOException { + out.beginObject(); + out.name("alg"); + out.value(value.getSignerAlgorithm()); + out.name("typ"); + out.value(value.getType()); + out.endObject(); + } + + @Override + public Header read(JsonReader in) throws IOException { + Header.Builder builder = new Header.Builder(); + in.beginObject(); + in.nextName(); + builder.signerAlgorithm(in.nextString()); + in.nextName(); + builder.type(in.nextString()); + in.endObject(); + return builder.build(); + } +} 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/json/JWTTokenRequestFormat.java new file mode 100644 index 0000000000..3f23a38c6c --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java @@ -0,0 +1,100 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.oauth.v2.json; + +import static com.google.common.base.Charsets.UTF_8; +import static com.google.common.base.Joiner.on; +import static com.google.common.io.BaseEncoding.base64Url; +import static org.jclouds.io.Payloads.newUrlEncodedFormPayload; + +import java.util.Set; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.http.HttpRequest; +import org.jclouds.io.Payload; +import org.jclouds.json.Json; +import org.jclouds.oauth.v2.domain.TokenRequest; +import org.jclouds.oauth.v2.domain.TokenRequestFormat; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.ImmutableSet; + +/** + * Formats a token request into JWT format namely: + * - transforms the token request to json + * - creates the base64 header.claimset portions of the payload. + * - uses the provided signer function to create a signature + * - creates the full url encoded payload as described in: + * https://developers.google.com/accounts/docs/OAuth2ServiceAccount + *

+ * + * @author David Alves + */ +@Singleton +public class JWTTokenRequestFormat implements TokenRequestFormat { + + private static final String ASSERTION_FORM_PARAM = "assertion"; + private static final String GRANT_TYPE_FORM_PARAM = "grant_type"; + private static final String GRANT_TYPE_JWT_BEARER = "urn:ietf:params:oauth:grant-type:jwt-bearer"; + + private final Function signer; + private final Json json; + + @Inject + public JWTTokenRequestFormat(Function signer, Json json) { + this.signer = signer; + this.json = json; + } + + @SuppressWarnings("unchecked") + @Override + public R formatRequest(R request, TokenRequest tokenRequest) { + + String encodedHeader = json.toJson(tokenRequest.getHeader()); + String encodedClaimSet = json.toJson(tokenRequest.getClaimSet()); + + encodedHeader = base64Url().omitPadding().encode(encodedHeader.getBytes(UTF_8)); + encodedClaimSet = base64Url().omitPadding().encode(encodedClaimSet.getBytes(UTF_8)); + + byte[] signature = signer.apply(on(".").join(encodedHeader, encodedClaimSet).getBytes(UTF_8)); + String encodedSignature = signature != null ? base64Url().omitPadding().encode(signature) : ""; + + // the final assertion in base 64 encoded {header}.{claimSet}.{signature} format + String assertion = on(".").join(encodedHeader, encodedClaimSet, encodedSignature); + Payload payload = newUrlEncodedFormPayload(ImmutableMultimap. builder() + .put(GRANT_TYPE_FORM_PARAM, GRANT_TYPE_JWT_BEARER) + .put(ASSERTION_FORM_PARAM, assertion).build()); + + return (R) request.toBuilder().payload(payload).build(); + } + + @Override + public String getTypeName() { + 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/resources/META-INF/services/org.jclouds.apis.ApiMetadata b/apis/oauth/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata new file mode 100644 index 0000000000..d5a96e463b --- /dev/null +++ b/apis/oauth/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata @@ -0,0 +1 @@ +org.jclouds.oauth.v2.OAuthApiMetadata diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java new file mode 100644 index 0000000000..5e4712e2d3 --- /dev/null +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java @@ -0,0 +1,42 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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 com.google.common.collect.ImmutableSet; +import com.google.common.reflect.TypeToken; +import org.jclouds.View; +import org.jclouds.apis.internal.BaseApiMetadataTest; +import org.testng.annotations.Test; + +/** + * Tests that OAuthApiMetadata is properly registered in ServiceLoader + *

+ *

+ * META-INF/services/org.jclouds.apis.ApiMetadata
+ * 
+ * + * @author Adrian Cole + */ +@Test(groups = "unit") +public class OAuthApiMetadataTest extends BaseApiMetadataTest { + + public OAuthApiMetadataTest() { + super(new OAuthApiMetadata(), ImmutableSet.>of()); + } +} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java new file mode 100644 index 0000000000..2d5fb5fa6f --- /dev/null +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java @@ -0,0 +1,81 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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 com.google.common.base.Charsets; +import com.google.common.base.Throwables; +import com.google.common.io.Files; +import org.jclouds.util.Strings2; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Properties; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; + +/** + * Utils for OAuth tests. + * + * @author David Alves + */ +public class OAuthTestUtils { + + public static Properties defaultProperties(Properties properties) { + try { + properties = properties == null ? new Properties() : properties; + properties.put("oauth.identity", "foo"); + properties.put("oauth.credential", Strings2.toStringAndClose(new FileInputStream("src/test/resources/testpk" + + ".pem"))); + properties.put("oauth.endpoint", "http://localhost:5000/o/oauth2/token"); + properties.put(AUDIENCE, "https://accounts.google.com/o/oauth2/token"); + return properties; + } catch (IOException e) { + throw Throwables.propagate(e); + } + } + + public static String setCredentialFromPemFile(Properties overrides, String key) { + String val = null; + String credentialFromFile = null; + String testKey = "test." + key; + + if (System.getProperties().containsKey(testKey)) { + val = System.getProperty(testKey); + } + checkNotNull(val, String.format("the property %s must be set (pem private key path)", testKey)); + + try { + credentialFromFile = Files.toString(new File(val), Charsets.UTF_8); + } catch (IOException e) { + throw Throwables.propagate(e); + } + overrides.setProperty(key, credentialFromFile); + return credentialFromFile; + } + + public static String getMandatoryProperty(Properties properties, String key) { + checkNotNull(properties); + checkNotNull(key); + String value = properties.getProperty(key); + return checkNotNull(value, String.format("mandatory property %s or test.%s was not present", key, key)); + } + +} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiExpectTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiExpectTest.java new file mode 100644 index 0000000000..d9f3017a1e --- /dev/null +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiExpectTest.java @@ -0,0 +1,103 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.features; + +import static com.google.common.base.Charsets.UTF_8; +import static com.google.common.io.BaseEncoding.base64Url; +import static org.testng.Assert.assertEquals; + +import java.net.URI; +import java.util.Properties; + +import javax.ws.rs.core.MediaType; + +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.oauth.v2.OAuthApi; +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.Token; +import org.jclouds.oauth.v2.domain.TokenRequest; +import org.jclouds.oauth.v2.internal.BaseOAuthApiExpectTest; +import org.testng.annotations.Test; + +/** + * Tests that a token requess is well formed. + * + * @author David Alves + */ +@Test(groups = "unit") +public class OAuthApiExpectTest extends BaseOAuthApiExpectTest { + + private static final String header = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}"; + + private static final String claims = "{\"iss\":\"761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer" + + ".gserviceaccount.com\"," + + "\"scope\":\"https://www.googleapis.com/auth/prediction\",\"aud\":\"https://accounts.google" + + ".com/o/oauth2/token\",\"exp\":1328573381,\"iat\":1328569781}"; + + private static final Token TOKEN = new Token.Builder().accessToken + ("1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M").tokenType("Bearer").expiresIn(3600).build(); + + private static final ClaimSet CLAIM_SET = new ClaimSet.Builder().addClaim("iss", + "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer" + + ".gserviceaccount.com") + .addClaim("scope", "https://www.googleapis.com/auth/prediction") + .addClaim("aud", "https://accounts.google.com/o/oauth2/token") + .expirationTime(1328573381) + .emissionTime(1328569781).build(); + + private static final Header HEADER = new Header.Builder().signerAlgorithm("RS256").type("JWT").build(); + + private static final String URL_ENCODED_TOKEN_REQUEST = + "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&" + + // Base64 Encoded Header + "assertion=" + base64Url().omitPadding().encode(header.getBytes(UTF_8)) + "." + + // Base64 Encoded Claims + base64Url().omitPadding().encode(claims.getBytes(UTF_8)) + "." + + // Base64 encoded {header}.{claims} signature (using SHA256) + "W2Lesr_98AzVYiMbzxFqmwcOjpIWlwqkC6pNn1fXND9oSDNNnFhy-AAR6DKH-x9ZmxbY80" + + "R5fH-OCeWumXlVgceKN8Z2SmgQsu8ElTpypQA54j_5j8vUImJ5hsOUYPeyF1U2BUzZ3L5g" + + "03PXBA0YWwRU9E1ChH28dQBYuGiUmYw"; + + private static final HttpRequest TOKEN_REQUEST = HttpRequest.builder() + .method("POST") + .endpoint(URI.create("http://localhost:5000/o/oauth2/token")) + .addHeader("Accept", MediaType.APPLICATION_JSON) + .payload(payloadFromStringWithContentType(URL_ENCODED_TOKEN_REQUEST, "application/x-www-form-urlencoded")) + .build(); + + private static final HttpResponse TOKEN_RESPONSE = HttpResponse.builder().statusCode(200).payload( + payloadFromString("{\n" + + " \"access_token\" : \"1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M\",\n" + + " \"token_type\" : \"Bearer\",\n" + + " \"expires_in\" : 3600\n" + + "}")).build(); + + @Override + protected Properties setupProperties() { + return OAuthTestUtils.defaultProperties(super.setupProperties()); + } + + public void testGenerateJWTRequest() { + OAuthApi api = requestSendsResponse(TOKEN_REQUEST, TOKEN_RESPONSE); + assertEquals(api.authenticate(new TokenRequest(HEADER, CLAIM_SET)), TOKEN); + } +} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java new file mode 100644 index 0000000000..994173a087 --- /dev/null +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java @@ -0,0 +1,85 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.features; + +import static com.google.common.base.Preconditions.checkState; +import static org.jclouds.oauth.v2.OAuthTestUtils.getMandatoryProperty; +import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; +import static org.jclouds.oauth.v2.config.OAuthProperties.SCOPES; +import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import java.util.Properties; + +import org.jclouds.oauth.v2.OAuthConstants; +import org.jclouds.oauth.v2.domain.ClaimSet; +import org.jclouds.oauth.v2.domain.Header; +import org.jclouds.oauth.v2.domain.Token; +import org.jclouds.oauth.v2.domain.TokenRequest; +import org.jclouds.oauth.v2.internal.BaseOAuthApiLiveTest; +import org.testng.annotations.Test; + +/** + * A live test for authentication. Requires the following properties to be set: + * - test.oauth.endpoint + * - test.oauth.identity + * - test.oauth.credential + * - test.jclouds.oauth.audience + * - test.jclouds.oauth.scopes + * - test.jclouds.oauth.signature-or-mac-algorithm + * + * @author David Alves + */ +@Test(groups = "live", singleThreaded = true) +public class OAuthApiLiveTest extends BaseOAuthApiLiveTest { + + private Properties properties; + + @Override + protected Properties setupProperties() { + properties = super.setupProperties(); + return properties; + + } + + @Test(groups = "live", singleThreaded = true) + public void testAuthenticateJWTToken() throws Exception { + assertTrue(properties != null, "properties were not set"); + String signatureAlgorithm = getMandatoryProperty(properties, SIGNATURE_OR_MAC_ALGORITHM); + checkState(OAuthConstants.OAUTH_ALGORITHM_NAMES_TO_SIGNATURE_ALGORITHM_NAMES.containsKey(signatureAlgorithm) + , String.format("Algorithm not supported: " + signatureAlgorithm)); + + Header header = Header.builder().signerAlgorithm(signatureAlgorithm).type("JWT").build(); + + String scopes = getMandatoryProperty(properties, SCOPES); + String audience = getMandatoryProperty(properties, AUDIENCE); + + long now = nowInSeconds(); + + ClaimSet claimSet = ClaimSet.builder().addClaim("aud", audience).addClaim("scope", scopes).addClaim("iss", + identity).emissionTime(now).expirationTime(now + 3600).build(); + + TokenRequest tokenRequest = TokenRequest.builder().header(header).claimSet(claimSet).build(); + Token token = api.authenticate(tokenRequest); + + assertNotNull(token, "no token when authenticating " + tokenRequest); + } +} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java new file mode 100644 index 0000000000..6454601f8d --- /dev/null +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java @@ -0,0 +1,60 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.Suppliers.ofInstance; +import static org.jclouds.util.Strings2.toStringAndClose; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import java.io.FileInputStream; +import java.io.IOException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.security.spec.InvalidKeySpecException; + +import org.jclouds.domain.Credentials; +import org.jclouds.oauth.v2.domain.OAuthCredentials; +import org.jclouds.oauth.v2.functions.OAuthCredentialsSupplier.OAuthCredentialsForCredentials; +import org.testng.annotations.Test; + +/** + * Test loading the credentials by extracting a pk from a PKCS12 keystore. + */ +@Test(groups = "unit") +public class OAuthCredentialsFromPKTest { + + public static OAuthCredentials loadOAuthCredentials() throws IOException, NoSuchAlgorithmException, + CertificateException, InvalidKeySpecException { + OAuthCredentialsSupplier loader = new OAuthCredentialsSupplier(ofInstance(new Credentials("foo", + toStringAndClose(new FileInputStream("src/test/resources/testpk.pem")))), new OAuthCredentialsForCredentials("RS256"), "RS256"); + return loader.get(); + } + + + public void testLoadPKString() throws IOException, NoSuchAlgorithmException, KeyStoreException, + CertificateException, UnrecoverableKeyException, InvalidKeySpecException { + OAuthCredentials creds = loadOAuthCredentials(); + assertNotNull(creds); + assertEquals(creds.identity, "foo"); + assertNotNull(creds.privateKey); + } +} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java new file mode 100644 index 0000000000..26ab759c5a --- /dev/null +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java @@ -0,0 +1,61 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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 com.google.common.base.Suppliers; +import org.jclouds.domain.Credentials; +import org.jclouds.oauth.v2.OAuthTestUtils; +import org.jclouds.rest.AuthorizationException; +import org.testng.annotations.Test; + +import java.util.Properties; + +import static org.jclouds.oauth.v2.functions.OAuthCredentialsSupplier.OAuthCredentialsForCredentials; +import static org.testng.Assert.assertNotNull; + +/** + * @author David Alves + */ +@Test(groups = "unit") +public class OAuthCredentialsSupplierTest { + + @Test(expectedExceptions = AuthorizationException.class) + public void testAuthorizationExceptionIsThrownOnBadKeys() { + OAuthCredentialsSupplier supplier = new OAuthCredentialsSupplier(Suppliers.ofInstance(new Credentials("MOMMA", + "MIA")), new OAuthCredentialsForCredentials("RS256"), "RS256"); + supplier.get(); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testGSEChildExceptionsPropagateAsAuthorizationException() { + OAuthCredentialsSupplier supplier = new OAuthCredentialsSupplier(Suppliers.ofInstance(new Credentials("MOMMA", + "MIA")), new OAuthCredentialsForCredentials("MOMMA"), "MOMMA"); + supplier.get(); + } + + public void testCredentialsAreLoadedOnRightAlgoAndCredentials() { + Properties propertied = OAuthTestUtils.defaultProperties(new Properties()); + Credentials validCredentials = new Credentials(propertied.getProperty("oauth.identity"), + propertied.getProperty("oauth.credential")); + OAuthCredentialsSupplier supplier = new OAuthCredentialsSupplier(Suppliers.ofInstance(validCredentials), + new OAuthCredentialsForCredentials("RS256"), "RS256"); + assertNotNull(supplier.get()); + } +} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/SignerFunctionTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/SignerFunctionTest.java new file mode 100644 index 0000000000..34c58bae79 --- /dev/null +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/SignerFunctionTest.java @@ -0,0 +1,65 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.Suppliers.ofInstance; +import static com.google.common.io.BaseEncoding.base64Url; +import static org.testng.Assert.assertNotNull; +import static org.testng.AssertJUnit.assertEquals; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.spec.InvalidKeySpecException; + +import org.testng.annotations.Test; + +/** + * Tests the SignOrProduceMacForToken + * + * @author David Alves + */ +@Test(groups = "unit") +public class SignerFunctionTest { + + private static final String PAYLOAD = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.\n" + + "eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZ" + + "GV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2ds" + + "ZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2x" + + "lLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU1NDM4NSwiaWF0IjoxMzI4NTUwNzg1fQ"; + + private static final String SHA256withRSA_PAYLOAD_SIGNATURE_RESULT = + "bmQrCv4gjkLWDK1JNJni74_kPiSDUMF_FImgqKJMUIgkDX1m2Sg3bH1yjF-cjBN7CvfAscnageo" + + "GtL2TGbwoTjJgUO5Yy0esavUUF-mBQHQtSw-2nL-9TNyM4SNi6fHPbgr83GGKOgA86r" + + "I9-nj3oUGd1fQty2k4Lsd-Zdkz6es"; + + + public void testSignPayload() throws InvalidKeyException, IOException, NoSuchAlgorithmException, + CertificateException, InvalidKeySpecException { + SignOrProduceMacForToken signer = new SignOrProduceMacForToken("RS256", + ofInstance(OAuthCredentialsFromPKTest + .loadOAuthCredentials())); + signer.loadSignatureOrMacOrNone(); + byte[] payloadSignature = signer.apply(PAYLOAD.getBytes(UTF_8)); + assertNotNull(payloadSignature); + + assertEquals(base64Url().omitPadding().encode(payloadSignature), SHA256withRSA_PAYLOAD_SIGNATURE_RESULT); + } +} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java new file mode 100644 index 0000000000..4b34c7ec24 --- /dev/null +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java @@ -0,0 +1,97 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.easymock.IArgumentMatcher; +import org.jclouds.http.HttpCommand; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +import java.net.URI; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.reportMatcher; +import static org.easymock.EasyMock.verify; + +/** + * @author Adrian Cole + */ +@Test(groups = "unit") +public class OAuthErrorHandlerTest { + + @Test + public void test409MakesIllegalStateException() { + assertCodeMakes( + "POST", + URI.create("http://oauth.org"), + 409, + "HTTP/1.1 409 Conflict", + "\"{\"code\":\"InvalidState\",\"message\":\"An incompatible transition has already been queued for this" + + " resource\"}\"", + IllegalStateException.class); + } + + private void assertCodeMakes(String method, URI uri, int statusCode, String message, String content, + Class expected) { + assertCodeMakes(method, uri, statusCode, message, "application/json", content, expected); + } + + private void assertCodeMakes(String method, URI uri, int statusCode, String message, String contentType, + String content, Class expected) { + + OAuthErrorHandler function = new OAuthErrorHandler(); + + HttpCommand command = createMock(HttpCommand.class); + HttpRequest request = HttpRequest.builder().method(method).endpoint(uri).build(); + HttpResponse response = HttpResponse.builder().statusCode(statusCode).message(message).payload(content).build(); + response.getPayload().getContentMetadata().setContentType(contentType); + + expect(command.getCurrentRequest()).andReturn(request).atLeastOnce(); + command.setException(classEq(expected)); + + replay(command); + + function.handleError(command, response); + + verify(command); + } + + public static Exception classEq(final Class in) { + reportMatcher(new IArgumentMatcher() { + + @Override + public void appendTo(StringBuffer buffer) { + buffer.append("classEq("); + buffer.append(in); + buffer.append(")"); + } + + @Override + public boolean matches(Object arg) { + return arg.getClass() == in; + } + + }); + return null; + } + +} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/Base64UrlSafeTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/Base64UrlSafeTest.java new file mode 100644 index 0000000000..d97b6010d6 --- /dev/null +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/Base64UrlSafeTest.java @@ -0,0 +1,45 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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 static com.google.common.base.Charsets.UTF_8; +import static com.google.common.io.BaseEncoding.base64Url; +import static org.testng.Assert.assertTrue; + +import org.testng.annotations.Test; + +/** + * Tests that the Base64 implementations used to Base64 encode the tokens are Url safe. + * + * @author David Alves + */ +@Test(groups = "unit") +public class Base64UrlSafeTest { + + public static final String STRING_THAT_GENERATES_URL_UNSAFE_BASE64_ENCODING = "§1234567890'+±!\"#$%&/()" + + "=?*qwertyuiopº´WERTYUIOPªàsdfghjklç~ASDFGHJKLÇ^ZXCVBNM;:_@€"; + + public void testUsedBase64IsUrlSafe() { + String encoded = base64Url().omitPadding().encode(STRING_THAT_GENERATES_URL_UNSAFE_BASE64_ENCODING.getBytes(UTF_8)); + assertTrue(!encoded.contains("+")); + assertTrue(!encoded.contains("/")); + assertTrue(!encoded.endsWith("=")); + } +} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiExpectTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiExpectTest.java new file mode 100644 index 0000000000..47ce105d6b --- /dev/null +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiExpectTest.java @@ -0,0 +1,28 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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 org.jclouds.oauth.v2.OAuthApi; + +/** + * @author Adrian Cole + */ +public class BaseOAuthApiExpectTest extends BaseOAuthExpectTest { + +} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java new file mode 100644 index 0000000000..d5d39041d5 --- /dev/null +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java @@ -0,0 +1,63 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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 static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.oauth.v2.OAuthTestUtils.setCredentialFromPemFile; +import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; +import static org.jclouds.oauth.v2.config.OAuthProperties.SCOPES; +import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; + +import java.util.Properties; +import java.util.concurrent.TimeUnit; + +import org.jclouds.apis.BaseApiLiveTest; +import org.jclouds.oauth.v2.OAuthApi; +import org.testng.annotations.Test; + +import com.google.common.base.Ticker; + + +/** + * @author David Alves + */ +@Test(groups = "live") +public class BaseOAuthApiLiveTest extends BaseApiLiveTest { + + public BaseOAuthApiLiveTest() { + provider = "oauth"; + } + + @Override + protected Properties setupProperties() { + Properties props = super.setupProperties(); + setCredentialFromPemFile(props, "oauth.credential"); + checkNotNull(setIfTestSystemPropertyPresent(props, "oauth.endpoint"), "test.oauth.endpoint must be set"); + checkNotNull(setIfTestSystemPropertyPresent(props, AUDIENCE), "test.jclouds.oauth.audience must be set"); + setIfTestSystemPropertyPresent(props, SCOPES); + setIfTestSystemPropertyPresent(props, SIGNATURE_OR_MAC_ALGORITHM); + return props; + } + + protected long nowInSeconds() { + return TimeUnit.SECONDS.convert(Ticker.systemTicker().read(), TimeUnit.NANOSECONDS); + } + +} + diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java new file mode 100644 index 0000000000..8f48c9a5ff --- /dev/null +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java @@ -0,0 +1,116 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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 static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static java.util.concurrent.TimeUnit.NANOSECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; +import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; +import static org.testng.Assert.assertNotNull; + +import java.io.Closeable; +import java.util.Properties; + +import org.jclouds.apis.BaseApiLiveTest; +import org.jclouds.config.ValueOfConfigurationKeyOrNull; +import org.jclouds.oauth.v2.OAuthApi; +import org.jclouds.oauth.v2.OAuthConstants; +import org.jclouds.oauth.v2.domain.ClaimSet; +import org.jclouds.oauth.v2.domain.Header; +import org.jclouds.oauth.v2.domain.Token; +import org.jclouds.oauth.v2.domain.TokenRequest; +import org.testng.annotations.Test; + +import com.google.common.base.Function; +import com.google.common.base.Ticker; +import com.google.common.reflect.TypeToken; +import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.Module; + +/** + * A base test of oauth authenticated rest providers. Providers must set the following properties: + *

+ * - oauth.endpoint + * - oauth.audience + * - oauth.signature-or-mac-algorithm + *

+ * - oauth.scopes is provided by the subclass + *

+ * This test asserts that a provider can authenticate with oauth for a given scope, or more simply + * that authentication/authorization is working. + * + * @author David Alves + */ + +@Test(groups = "live") +public abstract class BaseOAuthAuthenticatedApiLiveTest extends BaseApiLiveTest { + + protected abstract String getScopes(); + + private OAuthApi oauthApi; + + public void testAuthenticate() { + // obtain the necessary properties from the context + String signatureAlgorithm = checkNotNull(propFunction.apply(SIGNATURE_OR_MAC_ALGORITHM), + SIGNATURE_OR_MAC_ALGORITHM); + + checkState(OAuthConstants.OAUTH_ALGORITHM_NAMES_TO_SIGNATURE_ALGORITHM_NAMES.containsKey(signatureAlgorithm) + , String.format("Algorithm not supported: " + signatureAlgorithm)); + + String audience = checkNotNull(propFunction.apply(AUDIENCE), AUDIENCE); + + // obtain the scopes from the subclass + String scopes = getScopes(); + + Header header = Header.builder().signerAlgorithm(signatureAlgorithm).type("JWT").build(); + + long now = SECONDS.convert(Ticker.systemTicker().read(), NANOSECONDS); + + ClaimSet claimSet = ClaimSet.builder() + .addClaim("aud", audience) + .addClaim("scope", scopes) + .addClaim("iss", identity) + .emissionTime(now) + .expirationTime(now + 3600).build(); + + TokenRequest tokenRequest = TokenRequest.builder().header(header).claimSet(claimSet).build(); + + Token token = oauthApi.authenticate(tokenRequest); + + assertNotNull(token, "no token when authenticating " + tokenRequest); + } + + @SuppressWarnings({ "unchecked", "serial" }) + protected A create(Properties props, Iterable modules) { + Injector injector = newBuilder().modules(modules).overrides(props).buildInjector(); + propFunction = injector.getInstance(ValueOfConfigurationKeyOrNull.class); + try { + oauthApi = injector.getInstance(OAuthApi.class); + } catch (Exception e) { + throw new IllegalStateException("Provider has no OAuthApi bound. Was the OAuthAuthenticationModule added?"); + } + return (A) injector.getInstance(Key.get(new TypeToken(getClass()) { + }.getType())); + } + + private Function propFunction; +} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthExpectTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthExpectTest.java new file mode 100644 index 0000000000..4bb2da34a7 --- /dev/null +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthExpectTest.java @@ -0,0 +1,31 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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 org.jclouds.rest.internal.BaseRestApiExpectTest; + +/** + * @author Adrian Cole + */ +public class BaseOAuthExpectTest extends BaseRestApiExpectTest { + + public BaseOAuthExpectTest() { + provider = "oauth"; + } +} 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/json/JWTTokenRequestFormatTest.java new file mode 100644 index 0000000000..fc4b5a6287 --- /dev/null +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormatTest.java @@ -0,0 +1,75 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.jclouds.oauth.v2.json; + +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; + +import java.io.IOException; + +import org.jclouds.ContextBuilder; +import org.jclouds.http.HttpRequest; +import org.jclouds.oauth.v2.OAuthApiMetadata; +import org.jclouds.oauth.v2.OAuthTestUtils; +import org.jclouds.oauth.v2.domain.ClaimSet; +import org.jclouds.oauth.v2.domain.Header; +import org.jclouds.oauth.v2.domain.TokenRequest; +import org.jclouds.oauth.v2.domain.TokenRequestFormat; +import org.jclouds.util.Strings2; +import org.testng.annotations.Test; + +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; + +/** + * @author David Alves + */ +@Test(groups = "unit") +public class JWTTokenRequestFormatTest { + 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 + (OAuthTestUtils.defaultProperties(null)).build().utils() + .injector().getInstance(TokenRequestFormat.class); + Header header = new Header.Builder().signerAlgorithm("a").type("b").build(); + ClaimSet claimSet = new ClaimSet.Builder().addClaim("ist", STRING_THAT_GENERATES_URL_UNSAFE_BASE64_ENCODING) + .build(); + TokenRequest tokenRequest = new TokenRequest.Builder().claimSet(claimSet).header(header).build(); + HttpRequest request = tokenRequestFormat.formatRequest(HttpRequest.builder().method("GET").endpoint + ("http://localhost").build(), tokenRequest); + + assertNotNull(request.getPayload()); + + String payload = Strings2.toStringAndClose(request.getPayload().getInput()); + + // make sure the paylod is in the format {header}.{claims}.{signature} + Iterable parts = Splitter.on(".").split(payload); + + assertSame(Iterables.size(parts), 3); + + assertTrue(!payload.contains("+")); + assertTrue(!payload.contains("/")); + } +} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java new file mode 100644 index 0000000000..c550e8b3c7 --- /dev/null +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java @@ -0,0 +1,46 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.parse; + +import org.jclouds.json.BaseItemParserTest; +import org.jclouds.oauth.v2.domain.Token; +import org.testng.annotations.Test; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +/** + * @author David Alves + */ +@Test(groups = "unit") +public class ParseTokenTest extends BaseItemParserTest { + + @Override + public String resource() { + return "/tokenResponse.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public Token expected() { + return Token.builder().expiresIn(3600).tokenType("Bearer").accessToken + ("1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M").build(); + } +} diff --git a/apis/oauth/src/test/resources/logback.xml b/apis/oauth/src/test/resources/logback.xml new file mode 100644 index 0000000000..9679b2e03a --- /dev/null +++ b/apis/oauth/src/test/resources/logback.xml @@ -0,0 +1,38 @@ + + + + target/test-data/jclouds.log + + + %d %-5p [%c] [%thread] %m%n + + + + + target/test-data/jclouds-wire.log + + + %d %-5p [%c] [%thread] %m%n + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apis/oauth/src/test/resources/testpk.pem b/apis/oauth/src/test/resources/testpk.pem new file mode 100644 index 0000000000..1443074c78 --- /dev/null +++ b/apis/oauth/src/test/resources/testpk.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQCwqwzakEPP+U9vx9JCuMHebFIVQZ4Sjaj2RU9dJ6YT2s3u7dC6 +/0fGM5xm4fXmSHqyGC6PC8weQSkxnSpbU+R4jMWPM8ML4TIr5wP0avbg+wy3+WWI +of0MN7YHkCfqpaaiKiMw7niK1y07YvxJN8LX1xLpE7aXgIpn6L/qtJdHnQIDAQAB +AoGBAIAHlcsW3W3smPrC7sdXqXeNPHcXFH0RmC7Qz9EMmLiuyqqqQagitFsYr/GH +M3Ltd611BNi5jfUm97ly0m1ZAKp/nkTMVhfKfRIVsBDHtjQHcUOR9tr0LslptmaN +TG0bovbUohe5KwOqMK4YOjUQbInChVBrf7VrNQtv8e0eShdpAkEA3lzLP9QYfP1i +C4iYXqS7cgMDrs3qujC7PoyB54maen+Uvgyau1ZJpKMzXYkORPcYk+b71bl9jF80 +U+7LDnJjPwJBAMtksvL1V8DC5DYL43497JW4KBN4YZ3K7YWx/9gkvc3Q9VdXiUGu +6WKjmcbmsPI/jFdeO71uy934N8qEXLJcyiMCQQCTNKcxWD3l8PCJZiJI9ZFKBwjX +Hmb4X+51mBsfpw7nbbKQplOBFbynC4ujrmoN6e8RaubpNGUTGqvPrNQsejmNAkEA +lUDEAH4BczaQ+QgoXI9ceVG2NvNzzrMHMcC5Ggd8MPhR0VIvKsAMC5I6WjcXSe1Q +Mxy3gf84Ix7u8fHHhCuLOQJAQRhrlXiQUk4cJumNhjza5/+KtaV4FPbEQi+qcWE6 +tGoHPEBfbXyUdcUD4ae8X1W0yri0BuyVNaOCpGCBRIhPZA== +-----END RSA PRIVATE KEY----- diff --git a/apis/oauth/src/test/resources/tokenResponse.json b/apis/oauth/src/test/resources/tokenResponse.json new file mode 100644 index 0000000000..6717a550e9 --- /dev/null +++ b/apis/oauth/src/test/resources/tokenResponse.json @@ -0,0 +1,5 @@ +{ + "access_token" : "1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M", + "token_type" : "Bearer", + "expires_in" : 3600 +} \ No newline at end of file From 048e6384aa3eabfedf9cbd46c3fe1e32d7ecdf7a Mon Sep 17 00:00:00 2001 From: Andrew Bayer Date: Fri, 10 May 2013 16:30:27 -0700 Subject: [PATCH 02/33] JCLOUDS-23. Switch groupId to org.apache.jclouds, change parent POM, remove old distributionManagement content, add ASF repos. --- apis/oauth/pom.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apis/oauth/pom.xml b/apis/oauth/pom.xml index aa2cb253c5..74503fc88e 100644 --- a/apis/oauth/pom.xml +++ b/apis/oauth/pom.xml @@ -22,13 +22,13 @@ 4.0.0 - org.jclouds.labs + org.apache.jclouds.labs jclouds-labs-google 1.7.0-SNAPSHOT - org.jclouds.labs + org.apache.jclouds.labs oauth jclouds OAuth core jclouds components to access OAuth @@ -46,19 +46,19 @@ - org.jclouds + org.apache.jclouds jclouds-core ${jclouds.version} - org.jclouds + org.apache.jclouds jclouds-core ${jclouds.version} test-jar test - org.jclouds.driver + org.apache.jclouds.driver jclouds-slf4j ${jclouds.version} test From f08e98c6f0077739cc80f94d77693520087d88fd Mon Sep 17 00:00:00 2001 From: Andrew Bayer Date: Mon, 13 May 2013 10:46:01 -0700 Subject: [PATCH 03/33] JCLOUDS-30. Switch to 2 space indents for POM files. --- apis/oauth/pom.xml | 214 ++++++++++++++++++++++----------------------- 1 file changed, 107 insertions(+), 107 deletions(-) diff --git a/apis/oauth/pom.xml b/apis/oauth/pom.xml index 74503fc88e..8d32646e18 100644 --- a/apis/oauth/pom.xml +++ b/apis/oauth/pom.xml @@ -1,122 +1,122 @@ - 4.0.0 - - org.apache.jclouds.labs - jclouds-labs-google - 1.7.0-SNAPSHOT - - - + 4.0.0 + org.apache.jclouds.labs - oauth - jclouds OAuth core - jclouds components to access OAuth + jclouds-labs-google + 1.7.0-SNAPSHOT + - - FIX_ME - FIX_ME - FIX_ME - FIX_ME - FIX_ME - FIX_ME - 2 - - + + org.apache.jclouds.labs + oauth + jclouds OAuth core + jclouds components to access OAuth - - - org.apache.jclouds - jclouds-core - ${jclouds.version} - - - org.apache.jclouds - jclouds-core - ${jclouds.version} - test-jar - test - - - org.apache.jclouds.driver - jclouds-slf4j - ${jclouds.version} - test - - - ch.qos.logback - logback-classic - test - - + + FIX_ME + FIX_ME + FIX_ME + FIX_ME + FIX_ME + FIX_ME + 2 + + - + + + org.apache.jclouds + jclouds-core + ${jclouds.version} + + + org.apache.jclouds + jclouds-core + ${jclouds.version} + test-jar + test + + + org.apache.jclouds.driver + jclouds-slf4j + ${jclouds.version} + test + + + ch.qos.logback + logback-classic + test + + + + + + + maven-jar-plugin + + + + test-jar + + + + + + + + + + live + - - maven-jar-plugin - - - - test-jar - - - - + + org.apache.maven.plugins + maven-surefire-plugin + + + integration + integration-test + + test + + + + ${test.oauth.identity} + ${test.oauth.credential} + ${test.oauth.endpoint} + ${test.oauth.api-version} + ${test.oauth.build-version} + ${test.jclouds.oauth.signature-or-mac-algorithm>} + ${test.jclouds.oauth.audience} + ${test.jclouds.oauth.scopes} + + + + + - - - - - live - - - - org.apache.maven.plugins - maven-surefire-plugin - - - integration - integration-test - - test - - - - ${test.oauth.identity} - ${test.oauth.credential} - ${test.oauth.endpoint} - ${test.oauth.api-version} - ${test.oauth.build-version} - ${test.jclouds.oauth.signature-or-mac-algorithm>} - ${test.jclouds.oauth.audience} - ${test.jclouds.oauth.scopes} - - - - - - - - - + + + From a2d8925f0291281372f2bc8421bde67fdad50fb6 Mon Sep 17 00:00:00 2001 From: Andrew Bayer Date: Wed, 22 May 2013 10:29:56 -0400 Subject: [PATCH 04/33] JCLOUDS-80. Inherit apache-rat plugin config. --- .../services/org.jclouds.apis.ApiMetadata | 17 ++++++++++++++++ apis/oauth/src/test/resources/logback.xml | 20 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/apis/oauth/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata b/apis/oauth/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata index d5a96e463b..d7064de104 100644 --- a/apis/oauth/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata +++ b/apis/oauth/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata @@ -1 +1,18 @@ +# +# 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. +# + org.jclouds.oauth.v2.OAuthApiMetadata diff --git a/apis/oauth/src/test/resources/logback.xml b/apis/oauth/src/test/resources/logback.xml index 9679b2e03a..385a383568 100644 --- a/apis/oauth/src/test/resources/logback.xml +++ b/apis/oauth/src/test/resources/logback.xml @@ -1,4 +1,24 @@ + target/test-data/jclouds.log From 32279289c0eeba106ae869330b845fdf182b763d Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Wed, 22 May 2013 08:33:57 +0200 Subject: [PATCH 05/33] JCLOUDS-64: Update license headers --- apis/oauth/pom.xml | 26 ++++++++--------- .../java/org/jclouds/oauth/v2/OAuthApi.java | 28 +++++++++---------- .../jclouds/oauth/v2/OAuthApiMetadata.java | 28 +++++++++---------- .../org/jclouds/oauth/v2/OAuthConstants.java | 28 +++++++++---------- .../oauth/v2/config/Authentication.java | 28 +++++++++---------- .../v2/config/OAuthAuthenticationModule.java | 28 +++++++++---------- .../oauth/v2/config/OAuthHttpApiModule.java | 28 +++++++++---------- .../jclouds/oauth/v2/config/OAuthModule.java | 26 ++++++++--------- .../oauth/v2/config/OAuthProperties.java | 27 ++++++++---------- .../jclouds/oauth/v2/config/OAuthScopes.java | 27 ++++++++---------- .../org/jclouds/oauth/v2/domain/ClaimSet.java | 28 +++++++++---------- .../org/jclouds/oauth/v2/domain/Header.java | 28 +++++++++---------- .../oauth/v2/domain/OAuthCredentials.java | 28 +++++++++---------- .../org/jclouds/oauth/v2/domain/Token.java | 28 +++++++++---------- .../jclouds/oauth/v2/domain/TokenRequest.java | 28 +++++++++---------- .../oauth/v2/domain/TokenRequestFormat.java | 28 +++++++++---------- .../oauth/v2/filters/OAuthAuthenticator.java | 28 +++++++++---------- .../oauth/v2/functions/BuildTokenRequest.java | 26 ++++++++--------- .../oauth/v2/functions/FetchToken.java | 27 ++++++++---------- .../functions/OAuthCredentialsSupplier.java | 27 ++++++++---------- .../functions/SignOrProduceMacForToken.java | 26 ++++++++--------- .../oauth/v2/handlers/OAuthErrorHandler.java | 28 +++++++++---------- .../oauth/v2/handlers/OAuthTokenBinder.java | 28 +++++++++---------- .../oauth/v2/json/ClaimSetTypeAdapter.java | 28 +++++++++---------- .../oauth/v2/json/HeaderTypeAdapter.java | 28 +++++++++---------- .../oauth/v2/json/JWTTokenRequestFormat.java | 28 +++++++++---------- .../oauth/v2/OAuthApiMetadataTest.java | 28 +++++++++---------- .../org/jclouds/oauth/v2/OAuthTestUtils.java | 28 +++++++++---------- .../oauth/v2/features/OAuthApiExpectTest.java | 26 ++++++++--------- .../oauth/v2/features/OAuthApiLiveTest.java | 27 ++++++++---------- .../functions/OAuthCredentialsFromPKTest.java | 28 +++++++++---------- .../OAuthCredentialsSupplierTest.java | 27 ++++++++---------- .../v2/functions/SignerFunctionTest.java | 28 +++++++++---------- .../v2/handlers/OAuthErrorHandlerTest.java | 28 +++++++++---------- .../oauth/v2/internal/Base64UrlSafeTest.java | 27 ++++++++---------- .../v2/internal/BaseOAuthApiExpectTest.java | 28 +++++++++---------- .../v2/internal/BaseOAuthApiLiveTest.java | 28 +++++++++---------- .../BaseOAuthAuthenticatedApiLiveTest.java | 27 ++++++++---------- .../v2/internal/BaseOAuthExpectTest.java | 28 +++++++++---------- .../v2/json/JWTTokenRequestFormatTest.java | 27 ++++++++---------- .../oauth/v2/parse/ParseTokenTest.java | 27 ++++++++---------- 41 files changed, 518 insertions(+), 610 deletions(-) diff --git a/apis/oauth/pom.xml b/apis/oauth/pom.xml index 8d32646e18..854cb3c184 100644 --- a/apis/oauth/pom.xml +++ b/apis/oauth/pom.xml @@ -1,22 +1,20 @@ 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 2725778165..fa82431d55 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 @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * 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; 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 index a093d699b8..2c5e90af64 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * 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; diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java index 59fc43031c..fad18bbad4 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * 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; diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authentication.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authentication.java index b0b301d435..e929edb840 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authentication.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authentication.java @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * 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; 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 index 24a5d41652..39af1b7a82 100644 --- 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 @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * 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; 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 index 9234242ff5..220c5c3f75 100644 --- 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 @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * 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; 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 fc55a87da8..11c33bf270 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 @@ -1,20 +1,18 @@ /* - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 + * 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 + * 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. + * 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; 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 60fb13d726..fd316e8af6 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 @@ -1,22 +1,19 @@ /* - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 + * 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 + * 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. + * 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; /** diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java index f1136fe33b..8bb19036e3 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java @@ -1,22 +1,19 @@ /* - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 + * 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 + * 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. + * 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 javax.inject.Qualifier; diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java index 998ddcb08b..d64b94cc10 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * 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; 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 index ab4cd640a0..e6878403e3 100644 --- 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 @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * 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; diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java index bd2ee25fcb..78cb402d08 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * 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; diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java index 6ad47ea315..e27258f92e 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * 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; 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 index d2e6ab5bed..122226137d 100644 --- 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 @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * 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; 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 index 7d4ab63fc6..7364561185 100644 --- 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 @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * 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; 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 ccfd2a5ad4..f6dec92e74 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 @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * 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; 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 8faa22d342..d10b9a94fb 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 @@ -1,20 +1,18 @@ /* - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 + * 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 + * 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. + * 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; 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 a7975d92e4..cd3f3f5b22 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 @@ -1,22 +1,19 @@ /* - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 + * 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 + * 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. + * 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 com.google.common.base.Function; 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 d74bed52fe..68476ce35b 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 @@ -1,22 +1,19 @@ /* - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 + * 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 + * 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. + * 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 com.google.common.annotations.VisibleForTesting; 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 0d590a836e..0123d0aaa8 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 @@ -1,20 +1,18 @@ /* - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 + * 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 + * 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. + * 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; 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 f83c83373a..c4793f134f 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 @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * 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; 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 index 10ba408684..cb021eb030 100644 --- 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 @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * 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; diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java index b41a6b5030..fd8cdb7a5d 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.jclouds.oauth.v2.json; diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/HeaderTypeAdapter.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/HeaderTypeAdapter.java index a23d0c9cbd..f911a54752 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/HeaderTypeAdapter.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/HeaderTypeAdapter.java @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.jclouds.oauth.v2.json; 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/json/JWTTokenRequestFormat.java index 3f23a38c6c..6b514c94bc 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.jclouds.oauth.v2.json; diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java index 5e4712e2d3..41901eb340 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * 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; diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java index 2d5fb5fa6f..611a60af1b 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * 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; diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiExpectTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiExpectTest.java index d9f3017a1e..48944af3c4 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiExpectTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiExpectTest.java @@ -1,20 +1,18 @@ /* - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 + * 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 + * 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. + * 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.features; diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java index 994173a087..b608a1dd3b 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java @@ -1,22 +1,19 @@ /* - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 + * 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 + * 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. + * 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.features; import static com.google.common.base.Preconditions.checkState; diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java index 6454601f8d..435cabcd9c 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * 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; diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java index 26ab759c5a..8ab0fe910a 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java @@ -1,22 +1,19 @@ /* - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 + * 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 + * 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. + * 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 com.google.common.base.Suppliers; diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/SignerFunctionTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/SignerFunctionTest.java index 34c58bae79..797d003318 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/SignerFunctionTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/SignerFunctionTest.java @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * 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; diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java index 4b34c7ec24..f4e65e8cf9 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * 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; diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/Base64UrlSafeTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/Base64UrlSafeTest.java index d97b6010d6..c76b1affc6 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/Base64UrlSafeTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/Base64UrlSafeTest.java @@ -1,22 +1,19 @@ /* - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 + * 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 + * 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. + * 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 static com.google.common.base.Charsets.UTF_8; diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiExpectTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiExpectTest.java index 47ce105d6b..94d4f768dd 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiExpectTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiExpectTest.java @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * 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; diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java index d5d39041d5..7fc6dad87b 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * 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; diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java index 8f48c9a5ff..0294ff7fff 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java @@ -1,22 +1,19 @@ /* - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 + * 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 + * 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. + * 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 static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthExpectTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthExpectTest.java index 4bb2da34a7..1d7596cb58 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthExpectTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthExpectTest.java @@ -1,20 +1,18 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 +/* + * 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 + * 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. + * 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; 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/json/JWTTokenRequestFormatTest.java index fc4b5a6287..88672fe84f 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormatTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormatTest.java @@ -1,22 +1,19 @@ /* - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 + * 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 + * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.jclouds.oauth.v2.json; import static org.testng.Assert.assertNotNull; diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java index c550e8b3c7..8d82c4d231 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java @@ -1,22 +1,19 @@ /* - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds 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 + * 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 + * 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. + * 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.parse; import org.jclouds.json.BaseItemParserTest; From deafad060ca6b30d219becdc866910cf33470c4a Mon Sep 17 00:00:00 2001 From: Andrew Bayer Date: Fri, 24 May 2013 12:01:40 -0700 Subject: [PATCH 06/33] JCLOUDS-31. License header cleanup --- apis/oauth/src/test/resources/logback.xml | 26 +++++++++++------------ 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/apis/oauth/src/test/resources/logback.xml b/apis/oauth/src/test/resources/logback.xml index 385a383568..3a640aada6 100644 --- a/apis/oauth/src/test/resources/logback.xml +++ b/apis/oauth/src/test/resources/logback.xml @@ -1,22 +1,20 @@ From 7e2cebaec59f3d617d75438d8442cfed6e6b0281 Mon Sep 17 00:00:00 2001 From: Alex Heneveld Date: Tue, 29 Oct 2013 22:25:27 -0700 Subject: [PATCH 07/33] fix for JCLOUDS-360, replace platform-dependent assumption that nanosecond resolution ticker uses epoch 1970 as origin with guaranteed behaviour at millisecond-level resolution of System.currentTimeMillis --- .../oauth/v2/functions/BuildTokenRequest.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) 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 d10b9a94fb..1984028a11 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 @@ -23,7 +23,6 @@ import static org.jclouds.oauth.v2.config.OAuthProperties.SCOPES; import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; import java.util.Map; -import java.util.concurrent.TimeUnit; import javax.inject.Singleton; @@ -39,7 +38,6 @@ 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.base.Ticker; import com.google.common.collect.ImmutableMap; import com.google.common.reflect.Invokable; import com.google.inject.Inject; @@ -71,10 +69,15 @@ public class BuildTokenRequest implements Function timeSourceMillisSinceEpoch = new Supplier() { + @Override + public Long get() { + return System.currentTimeMillis(); + } + }; + @Inject public BuildTokenRequest(@Named(AUDIENCE) String assertionTargetDescription, @Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureAlgorithm, @@ -89,7 +92,7 @@ public class BuildTokenRequest implements Function Date: Mon, 11 Nov 2013 14:44:27 +0000 Subject: [PATCH 08/33] JCLOUDS-372: changing OAuth timeout from MINUTES to SECONDS --- .../java/org/jclouds/oauth/v2/config/OAuthModule.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) 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 11c33bf270..cc99444988 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 @@ -66,9 +66,12 @@ public class OAuthModule extends AbstractModule { } /** - * Provides a cache for tokens. Cache is time based and expires after 59 minutes (the maximum time a token is - * valid is 60 minutes) + * 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 provideAccessCache(Function getAccess, @@ -78,7 +81,7 @@ public class OAuthModule extends AbstractModule { // bit before the deadline to make sure there aren't session expiration exceptions sessionIntervalInSeconds = sessionIntervalInSeconds > 30 ? sessionIntervalInSeconds - 30 : sessionIntervalInSeconds; - return CacheBuilder.newBuilder().expireAfterWrite(sessionIntervalInSeconds, TimeUnit.MINUTES).build(CacheLoader + return CacheBuilder.newBuilder().expireAfterWrite(sessionIntervalInSeconds, TimeUnit.SECONDS).build(CacheLoader .from(getAccess)); } From 61b99641acd552a8eb7d4bf85a8b17d72b20c0b6 Mon Sep 17 00:00:00 2001 From: Rick Wright Date: Mon, 18 Nov 2013 10:39:55 -0800 Subject: [PATCH 09/33] Fix Live Tests for JCLOUDS-360 which rely on platform-dependent nanoseconds. --- .../org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java | 4 +--- .../oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java | 5 ++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java index 7fc6dad87b..e4f483e671 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java @@ -29,8 +29,6 @@ import org.jclouds.apis.BaseApiLiveTest; import org.jclouds.oauth.v2.OAuthApi; import org.testng.annotations.Test; -import com.google.common.base.Ticker; - /** * @author David Alves @@ -54,7 +52,7 @@ public class BaseOAuthApiLiveTest extends BaseApiLiveTest { } protected long nowInSeconds() { - return TimeUnit.SECONDS.convert(Ticker.systemTicker().read(), TimeUnit.NANOSECONDS); + return TimeUnit.SECONDS.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS); } } diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java index 0294ff7fff..d2fbd91f70 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java @@ -17,7 +17,7 @@ package org.jclouds.oauth.v2.internal; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; -import static java.util.concurrent.TimeUnit.NANOSECONDS; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.SECONDS; import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; @@ -37,7 +37,6 @@ import org.jclouds.oauth.v2.domain.TokenRequest; import org.testng.annotations.Test; import com.google.common.base.Function; -import com.google.common.base.Ticker; import com.google.common.reflect.TypeToken; import com.google.inject.Injector; import com.google.inject.Key; @@ -80,7 +79,7 @@ public abstract class BaseOAuthAuthenticatedApiLiveTest ext Header header = Header.builder().signerAlgorithm(signatureAlgorithm).type("JWT").build(); - long now = SECONDS.convert(Ticker.systemTicker().read(), NANOSECONDS); + long now = SECONDS.convert(System.currentTimeMillis(), MILLISECONDS); ClaimSet claimSet = ClaimSet.builder() .addClaim("aud", audience) From b17adea8798832f18dfd2d28a954230d72515663 Mon Sep 17 00:00:00 2001 From: Andrew Gaul Date: Sun, 1 Dec 2013 23:19:24 -0800 Subject: [PATCH 10/33] Address Checkstyle violations --- .../org/jclouds/oauth/v2/domain/TokenRequestFormat.java | 6 +++--- .../oauth/v2/functions/OAuthCredentialsSupplier.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) 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 index 7364561185..25925e4e06 100644 --- 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 @@ -33,15 +33,15 @@ public interface TokenRequestFormat { /** * Transforms the provided HttpRequest into a particular token request with a specific format. */ - public R formatRequest(R httpRequest, TokenRequest tokenRequest); + R formatRequest(R httpRequest, TokenRequest tokenRequest); /** * The name of the type of the token request, e.g., "JWT" */ - public String getTypeName(); + String getTypeName(); /** * The claims that must be present in the token request for it to be valid. */ - public Set requiredClaims(); + Set requiredClaims(); } 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 68476ce35b..e204e8f2bb 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 @@ -115,7 +115,7 @@ public class OAuthCredentialsSupplier implements Supplier { } catch (UncheckedExecutionException e) { Throwable authorizationException = getFirstThrowableOfType(e, AuthorizationException.class); if (authorizationException != null) { - throw ((AuthorizationException) authorizationException); + throw (AuthorizationException) authorizationException; } throw propagate(e); } From f6dc1f39a369fbc9de1c7e07231d274fc9fe31af Mon Sep 17 00:00:00 2001 From: Andrew Gaul Date: Wed, 11 Dec 2013 17:29:36 -0800 Subject: [PATCH 11/33] Enforce no unused imports via Checkstyle Removed with: mvn checkstyle:checkstyle --quiet -Dcheckstyle.output.file=/dev/stdout -Dcheckstyle.output.format=plain | tac | while read i; do echo $i | sed -n 's/\([^:]*\):\([^:]*\):.*/sed -i \2d \1/p' | bash; done --- .../src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java | 1 - 1 file changed, 1 deletion(-) 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 index 2c5e90af64..9dd71d628d 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java @@ -22,7 +22,6 @@ import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGOR 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; From e2e61c4885198ffbedf145e404565ad9546c70fd Mon Sep 17 00:00:00 2001 From: Andrew Bayer Date: Tue, 17 Dec 2013 11:51:02 -0800 Subject: [PATCH 12/33] Updating to 1.8.0-SNAPSHOT --- apis/oauth/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apis/oauth/pom.xml b/apis/oauth/pom.xml index 854cb3c184..b58c385a1f 100644 --- a/apis/oauth/pom.xml +++ b/apis/oauth/pom.xml @@ -22,7 +22,7 @@ org.apache.jclouds.labs jclouds-labs-google - 1.7.0-SNAPSHOT + 1.8.0-SNAPSHOT From 1e48a1daeae90b8cc5b08dec3578f58c5c30e28a Mon Sep 17 00:00:00 2001 From: Andrew Gaul Date: Fri, 16 May 2014 09:49:16 -0700 Subject: [PATCH 13/33] Make constants final classes instead of interfaces This commit prohibits implementation of the empty interface and instantiation of the class. Refer to _Effective Java_ item 19 for more background. --- .../src/main/java/org/jclouds/oauth/v2/OAuthConstants.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java index fad18bbad4..d3953f36c3 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java @@ -25,7 +25,7 @@ import java.util.Map; * * @author David Alves */ -public class OAuthConstants { +public final class OAuthConstants { /** * Selected algorithm when a signature or mac isn't required. @@ -73,4 +73,8 @@ public class OAuthConstants { * The (optional) set of additional claims to use, provided in Map form */ public static final String ADDITIONAL_CLAIMS = "jclouds.oauth.additional-claims"; + + private OAuthConstants() { + throw new AssertionError("intentionally unimplemented"); + } } From a85b91904f8eda1506cf4ea95a73fa05ca3bc2d5 Mon Sep 17 00:00:00 2001 From: Andrew Gaul Date: Sat, 17 May 2014 00:39:09 -0700 Subject: [PATCH 14/33] Migrate InputSupplier callers to ByteSource A future version of Guava will remove InputSupplier. --- .../oauth/v2/functions/OAuthCredentialsSupplier.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 e204e8f2bb..4d57d15df0 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 @@ -17,10 +17,12 @@ 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; @@ -40,7 +42,6 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Throwables.propagate; import static java.lang.String.format; import static org.jclouds.crypto.Pems.privateKeySpec; -import static org.jclouds.io.Payloads.newStringPayload; import static org.jclouds.oauth.v2.OAuthConstants.NO_ALGORITHM; import static org.jclouds.oauth.v2.OAuthConstants.OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES; import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; @@ -92,7 +93,8 @@ public class OAuthCredentialsSupplier implements Supplier { return new OAuthCredentials.Builder().identity(identity).credential(privateKeyInPemFormat).build(); } KeyFactory keyFactory = KeyFactory.getInstance(keyFactoryAlgorithm); - PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec(newStringPayload(privateKeyInPemFormat))); + PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec(ByteSource.wrap( + privateKeyInPemFormat.getBytes(Charsets.UTF_8)))); return new OAuthCredentials.Builder().identity(identity).credential(privateKeyInPemFormat) .privateKey(privateKey).build(); } catch (IOException e) { From 289197a560934e3c2e4a5b43936b419512d5f0cc Mon Sep 17 00:00:00 2001 From: Andrew Gaul Date: Thu, 22 May 2014 00:26:03 -0700 Subject: [PATCH 15/33] Prefer Guava Files over FileInputStream This ensures proper resource handling. --- .../test/java/org/jclouds/oauth/v2/OAuthTestUtils.java | 6 ++---- .../oauth/v2/functions/OAuthCredentialsFromPKTest.java | 9 ++++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java index 611a60af1b..35eb9b10f3 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java @@ -19,10 +19,8 @@ package org.jclouds.oauth.v2; import com.google.common.base.Charsets; import com.google.common.base.Throwables; import com.google.common.io.Files; -import org.jclouds.util.Strings2; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.util.Properties; @@ -40,8 +38,8 @@ public class OAuthTestUtils { try { properties = properties == null ? new Properties() : properties; properties.put("oauth.identity", "foo"); - properties.put("oauth.credential", Strings2.toStringAndClose(new FileInputStream("src/test/resources/testpk" + - ".pem"))); + properties.put("oauth.credential", + Files.asCharSource(new File("src/test/resources/testpk.pem"), Charsets.UTF_8).read()); properties.put("oauth.endpoint", "http://localhost:5000/o/oauth2/token"); properties.put(AUDIENCE, "https://accounts.google.com/o/oauth2/token"); return properties; diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java index 435cabcd9c..e3794d6943 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java @@ -17,11 +17,10 @@ package org.jclouds.oauth.v2.functions; import static com.google.common.base.Suppliers.ofInstance; -import static org.jclouds.util.Strings2.toStringAndClose; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; -import java.io.FileInputStream; +import java.io.File; import java.io.IOException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; @@ -29,6 +28,9 @@ import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.security.spec.InvalidKeySpecException; +import com.google.common.base.Charsets; +import com.google.common.io.Files; + import org.jclouds.domain.Credentials; import org.jclouds.oauth.v2.domain.OAuthCredentials; import org.jclouds.oauth.v2.functions.OAuthCredentialsSupplier.OAuthCredentialsForCredentials; @@ -43,7 +45,8 @@ public class OAuthCredentialsFromPKTest { public static OAuthCredentials loadOAuthCredentials() throws IOException, NoSuchAlgorithmException, CertificateException, InvalidKeySpecException { OAuthCredentialsSupplier loader = new OAuthCredentialsSupplier(ofInstance(new Credentials("foo", - toStringAndClose(new FileInputStream("src/test/resources/testpk.pem")))), new OAuthCredentialsForCredentials("RS256"), "RS256"); + Files.asCharSource(new File("src/test/resources/testpk.pem"), Charsets.UTF_8).read())), + new OAuthCredentialsForCredentials("RS256"), "RS256"); return loader.get(); } From e608c35a0223d4d9f1b976fa77a8831b5acab32c Mon Sep 17 00:00:00 2001 From: Andrew Gaul Date: Sat, 7 Jun 2014 21:13:36 -0700 Subject: [PATCH 16/33] JCLOUDS-546: Remove Javadoc @author annotations Annotations removed with: find -name \*.java | xargs sed -i /@author/d Empty Javadoc removed with multiple iterations of: find -name \*.java | xargs sed -i -z 's/ \*\n \*\// \*\//' find -name \*.java | xargs sed -i -z 's/ \* \n \*\// \*\//' find -name \*.java | xargs sed -i -z 's/\/\*\*\n \*\/\n//' --- apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApi.java | 1 - .../src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java | 2 -- .../src/main/java/org/jclouds/oauth/v2/OAuthConstants.java | 2 -- .../main/java/org/jclouds/oauth/v2/config/Authentication.java | 1 - .../org/jclouds/oauth/v2/config/OAuthAuthenticationModule.java | 2 -- .../java/org/jclouds/oauth/v2/config/OAuthHttpApiModule.java | 2 -- .../src/main/java/org/jclouds/oauth/v2/config/OAuthModule.java | 2 -- .../main/java/org/jclouds/oauth/v2/config/OAuthProperties.java | 2 -- .../src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java | 2 -- .../src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java | 1 - .../src/main/java/org/jclouds/oauth/v2/domain/Header.java | 1 - .../oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java | 2 -- .../main/java/org/jclouds/oauth/v2/domain/TokenRequest.java | 2 -- .../java/org/jclouds/oauth/v2/domain/TokenRequestFormat.java | 2 -- .../java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java | 2 -- .../java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java | 2 -- .../main/java/org/jclouds/oauth/v2/functions/FetchToken.java | 3 --- .../jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java | 1 - .../jclouds/oauth/v2/functions/SignOrProduceMacForToken.java | 2 -- .../java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java | 2 -- .../java/org/jclouds/oauth/v2/handlers/OAuthTokenBinder.java | 2 -- .../java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java | 2 -- .../java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java | 2 -- .../test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java | 2 -- .../src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java | 2 -- .../java/org/jclouds/oauth/v2/features/OAuthApiExpectTest.java | 2 -- .../java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java | 2 -- .../oauth/v2/functions/OAuthCredentialsSupplierTest.java | 3 --- .../org/jclouds/oauth/v2/functions/SignerFunctionTest.java | 2 -- .../org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java | 3 --- .../java/org/jclouds/oauth/v2/internal/Base64UrlSafeTest.java | 2 -- .../org/jclouds/oauth/v2/internal/BaseOAuthApiExpectTest.java | 3 --- .../org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java | 3 --- .../oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java | 2 -- .../org/jclouds/oauth/v2/internal/BaseOAuthExpectTest.java | 3 --- .../org/jclouds/oauth/v2/json/JWTTokenRequestFormatTest.java | 3 --- .../test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java | 3 --- 37 files changed, 77 deletions(-) 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 fa82431d55..12e8fcbb92 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 @@ -38,7 +38,6 @@ import org.jclouds.rest.annotations.Endpoint; * OAuthAuthenticator as a request filter, which in turn uses this class to * perform token requests. * - * @author David Alves * @see OAuthAsyncApi */ @Endpoint(Authentication.class) 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 index 9dd71d628d..3ef26e69c7 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java @@ -31,8 +31,6 @@ import com.google.inject.Module; /** * Implementation of {@link ApiMetadata} for OAuth 2 API - * - * @author David Alves */ public class OAuthApiMetadata extends BaseHttpApiMetadata { diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java index d3953f36c3..9b140d46d9 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java @@ -22,8 +22,6 @@ import java.util.Map; /** * The constants for OAuth \ - * - * @author David Alves */ public final class OAuthConstants { diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authentication.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authentication.java index e929edb840..4f1107a0b7 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authentication.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authentication.java @@ -26,7 +26,6 @@ import java.lang.annotation.Target; /** * Qualifies OAuth related resources, such as Endpoint. * - * @author David Alves * @see org.jclouds.oauth.v2.OAuthAsyncApi */ @Retention(value = RetentionPolicy.RUNTIME) 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 index 39af1b7a82..fb2d4137cc 100644 --- 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 @@ -32,8 +32,6 @@ import com.google.inject.Provides; /** * An OAuth module to be used form other providers. - * - * @author David Alves */ public class OAuthAuthenticationModule extends AbstractModule { 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 index 220c5c3f75..6b4fdf959e 100644 --- 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 @@ -31,8 +31,6 @@ import com.google.inject.Provides; /** * OAuth module to when accessing OAuth stand-alone. - * - * @author David Alves */ @ConfiguresHttpApi public class OAuthHttpApiModule extends HttpApiModule { 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 cc99444988..11fca2f982 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 @@ -48,8 +48,6 @@ import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; /** * Base OAuth module - * - * @author David Alves */ public class OAuthModule extends AbstractModule { 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 fd316e8af6..7b1bf17fce 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 @@ -18,8 +18,6 @@ package org.jclouds.oauth.v2.config; /** * Configurable properties for jclouds OAuth - * - * @author David Alves */ public class OAuthProperties { diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java index 8bb19036e3..57ffd29b4a 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java @@ -26,8 +26,6 @@ import java.lang.annotation.Target; * Used to annotate REST methods/ifaces that use OAuthAuthentication. *

* Sets the scopes for the token request for that particular method. - * - * @author David Alves */ @Retention(value = RetentionPolicy.RUNTIME) @Target(value = {ElementType.TYPE, ElementType.METHOD}) diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java index d64b94cc10..5c0b348d0f 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java @@ -35,7 +35,6 @@ import static com.google.common.base.Preconditions.checkState; /** * The claimset for the token. * - * @author David Alves * @see doc 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 index e6878403e3..c230e1da4c 100644 --- 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 @@ -25,7 +25,6 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * The header for the OAuth token, contains the signer algorithm's name and the type of the token * - * @author David Alves * @see doc */ public class Header { diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java index e27258f92e..a18a7eb6e3 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java @@ -26,8 +26,6 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * The oauth token, obtained upon a successful token request and ready to embed in requests. - * - * @author David Alves */ public class Token { 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 index 122226137d..7d1a6a4438 100644 --- 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 @@ -24,8 +24,6 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * A complete token request. - * - * @author David Alves */ public class TokenRequest { 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 index 25925e4e06..f4b80c177f 100644 --- 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 @@ -24,8 +24,6 @@ import java.util.Set; /** * Transforms a TokenRequest into a specific format (e.g. JWT token) - * - * @author David Alves */ @ImplementedBy(JWTTokenRequestFormat.class) public interface TokenRequestFormat { 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 f6dec92e74..e25bc201e1 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 @@ -34,8 +34,6 @@ import static com.google.common.base.Preconditions.checkState; * 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 - * - * @author David Alves */ @Singleton public class OAuthAuthenticator implements HttpRequestFilter { 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 1984028a11..7b869dcfc0 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 @@ -49,8 +49,6 @@ import com.google.inject.name.Named; * Builds the default token request with the following claims: iss,scope,aud,iat,exp. *

* TODO scopes etc should come from the REST method and not from a global property - * - * @author David Alves */ @Singleton public class BuildTokenRequest implements Function { 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 cd3f3f5b22..593c8852ec 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 @@ -24,9 +24,6 @@ import org.jclouds.oauth.v2.domain.TokenRequest; import javax.inject.Inject; import javax.inject.Singleton; -/** - * @author David Alves - */ @Singleton public class FetchToken implements Function { 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 4d57d15df0..45620c0eb9 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 @@ -51,7 +51,6 @@ import static org.jclouds.util.Throwables2.getFirstThrowableOfType; * 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. * - * @author David Alves * @see org.jclouds.oauth.v2.OAuthConstants#OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES */ @Singleton 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 0123d0aaa8..471812a8b1 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 @@ -40,8 +40,6 @@ import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGOR /** * Function that signs/produces mac's for OAuth tokens, provided a {@link Signature} or a {@link Mac} algorithm and * {@link PrivateKey} - * - * @author David Alves */ public class SignOrProduceMacForToken implements Function { 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 c4793f134f..78d78440f7 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 @@ -30,8 +30,6 @@ import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream; /** * This will parse and set an appropriate exception on the command object. - * - * @author David Alves */ @Singleton public class OAuthErrorHandler implements HttpErrorHandler { 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 index cb021eb030..1030804714 100644 --- 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 @@ -27,8 +27,6 @@ import javax.inject.Singleton; /** * Generic implementation of a token binder. Uses a provided {@link TokenRequestFormat} to actually bind tokens to * requests. - * - * @author David Alves */ @Singleton public class OAuthTokenBinder implements Binder { diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java index fd8cdb7a5d..62b3a26991 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java @@ -27,8 +27,6 @@ import java.util.Map; /** * JSON TypeAdapter for the ClaimSet type. Pull the claims maps to the root level and adds two properties for the * expiration time and issuing time. - * - * @author David Alves */ public class ClaimSetTypeAdapter extends TypeAdapter { 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/json/JWTTokenRequestFormat.java index 6b514c94bc..265cb26075 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java @@ -44,8 +44,6 @@ import com.google.common.collect.ImmutableSet; * - creates the full url encoded payload as described in: * https://developers.google.com/accounts/docs/OAuth2ServiceAccount *

- * - * @author David Alves */ @Singleton public class JWTTokenRequestFormat implements TokenRequestFormat { diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java index 41901eb340..d6ea17f60d 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java @@ -28,8 +28,6 @@ import org.testng.annotations.Test; *

  * META-INF/services/org.jclouds.apis.ApiMetadata
  * 
- * - * @author Adrian Cole */ @Test(groups = "unit") public class OAuthApiMetadataTest extends BaseApiMetadataTest { diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java index 35eb9b10f3..28879a98ce 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java @@ -29,8 +29,6 @@ import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; /** * Utils for OAuth tests. - * - * @author David Alves */ public class OAuthTestUtils { diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiExpectTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiExpectTest.java index 48944af3c4..2008e5dddd 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiExpectTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiExpectTest.java @@ -38,8 +38,6 @@ import org.testng.annotations.Test; /** * Tests that a token requess is well formed. - * - * @author David Alves */ @Test(groups = "unit") public class OAuthApiExpectTest extends BaseOAuthApiExpectTest { diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java index b608a1dd3b..4ac59508a4 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java @@ -42,8 +42,6 @@ import org.testng.annotations.Test; * - test.jclouds.oauth.audience * - test.jclouds.oauth.scopes * - test.jclouds.oauth.signature-or-mac-algorithm - * - * @author David Alves */ @Test(groups = "live", singleThreaded = true) public class OAuthApiLiveTest extends BaseOAuthApiLiveTest { diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java index 8ab0fe910a..2b3d094f40 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java @@ -27,9 +27,6 @@ import java.util.Properties; import static org.jclouds.oauth.v2.functions.OAuthCredentialsSupplier.OAuthCredentialsForCredentials; import static org.testng.Assert.assertNotNull; -/** - * @author David Alves - */ @Test(groups = "unit") public class OAuthCredentialsSupplierTest { diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/SignerFunctionTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/SignerFunctionTest.java index 797d003318..2a64822ce6 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/SignerFunctionTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/SignerFunctionTest.java @@ -31,8 +31,6 @@ import org.testng.annotations.Test; /** * Tests the SignOrProduceMacForToken - * - * @author David Alves */ @Test(groups = "unit") public class SignerFunctionTest { diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java index f4e65e8cf9..255c5c7f65 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java @@ -30,9 +30,6 @@ import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.reportMatcher; import static org.easymock.EasyMock.verify; -/** - * @author Adrian Cole - */ @Test(groups = "unit") public class OAuthErrorHandlerTest { diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/Base64UrlSafeTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/Base64UrlSafeTest.java index c76b1affc6..f6d938a868 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/Base64UrlSafeTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/Base64UrlSafeTest.java @@ -24,8 +24,6 @@ import org.testng.annotations.Test; /** * Tests that the Base64 implementations used to Base64 encode the tokens are Url safe. - * - * @author David Alves */ @Test(groups = "unit") public class Base64UrlSafeTest { diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiExpectTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiExpectTest.java index 94d4f768dd..a44bad175d 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiExpectTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiExpectTest.java @@ -18,9 +18,6 @@ package org.jclouds.oauth.v2.internal; import org.jclouds.oauth.v2.OAuthApi; -/** - * @author Adrian Cole - */ public class BaseOAuthApiExpectTest extends BaseOAuthExpectTest { } diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java index e4f483e671..ee1149002b 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java @@ -30,9 +30,6 @@ import org.jclouds.oauth.v2.OAuthApi; import org.testng.annotations.Test; -/** - * @author David Alves - */ @Test(groups = "live") public class BaseOAuthApiLiveTest extends BaseApiLiveTest { diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java index d2fbd91f70..aefdcdd934 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java @@ -53,8 +53,6 @@ import com.google.inject.Module; *

* This test asserts that a provider can authenticate with oauth for a given scope, or more simply * that authentication/authorization is working. - * - * @author David Alves */ @Test(groups = "live") diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthExpectTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthExpectTest.java index 1d7596cb58..18fe151ea5 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthExpectTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthExpectTest.java @@ -18,9 +18,6 @@ package org.jclouds.oauth.v2.internal; import org.jclouds.rest.internal.BaseRestApiExpectTest; -/** - * @author Adrian Cole - */ public class BaseOAuthExpectTest extends BaseRestApiExpectTest { public BaseOAuthExpectTest() { 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/json/JWTTokenRequestFormatTest.java index 88672fe84f..fa3307fd7e 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormatTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormatTest.java @@ -36,9 +36,6 @@ import org.testng.annotations.Test; import com.google.common.base.Splitter; import com.google.common.collect.Iterables; -/** - * @author David Alves - */ @Test(groups = "unit") public class JWTTokenRequestFormatTest { public static final String STRING_THAT_GENERATES_URL_UNSAFE_BASE64_ENCODING = "§1234567890'+±!\"#$%&/()" + diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java index 8d82c4d231..bcaa9e4a48 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java @@ -23,9 +23,6 @@ import org.testng.annotations.Test; import javax.ws.rs.Consumes; import javax.ws.rs.core.MediaType; -/** - * @author David Alves - */ @Test(groups = "unit") public class ParseTokenTest extends BaseItemParserTest { From a6ad6d463d452e8d65042f0269571390247824fb Mon Sep 17 00:00:00 2001 From: Andrew Phillips Date: Tue, 5 Aug 2014 11:46:53 +0200 Subject: [PATCH 17/33] Updating project and jclouds.version to 2.0.0-SNAPSHOT --- apis/oauth/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apis/oauth/pom.xml b/apis/oauth/pom.xml index b58c385a1f..31d34ac287 100644 --- a/apis/oauth/pom.xml +++ b/apis/oauth/pom.xml @@ -22,7 +22,7 @@ org.apache.jclouds.labs jclouds-labs-google - 1.8.0-SNAPSHOT + 2.0.0-SNAPSHOT From 5c1e36e5d19bc211196b1973d119f2c16ce40167 Mon Sep 17 00:00:00 2001 From: Andrew Gaul Date: Fri, 8 Aug 2014 11:49:42 -0700 Subject: [PATCH 18/33] JCLOUDS-653: Address Guava 18 deprecations Mostly renaming Objects.toStringHelper to MoreObjects.toStringHelper. --- .../src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java | 4 ++-- .../src/main/java/org/jclouds/oauth/v2/domain/Header.java | 5 +++-- .../java/org/jclouds/oauth/v2/domain/OAuthCredentials.java | 5 +++-- .../src/main/java/org/jclouds/oauth/v2/domain/Token.java | 5 +++-- .../main/java/org/jclouds/oauth/v2/domain/TokenRequest.java | 5 +++-- 5 files changed, 14 insertions(+), 10 deletions(-) diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java index 5c0b348d0f..214347410d 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java @@ -26,9 +26,9 @@ import com.google.common.collect.Sets; import java.util.Map; import java.util.Set; -import static com.google.common.base.Objects.ToStringHelper; +import static com.google.common.base.MoreObjects.ToStringHelper; +import static com.google.common.base.MoreObjects.toStringHelper; import static com.google.common.base.Objects.equal; -import static com.google.common.base.Objects.toStringHelper; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; 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 index c230e1da4c..baacc115d0 100644 --- 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 @@ -16,10 +16,11 @@ */ package org.jclouds.oauth.v2.domain; +import com.google.common.base.MoreObjects; import com.google.common.base.Objects; +import static com.google.common.base.MoreObjects.toStringHelper; import static com.google.common.base.Objects.equal; -import static com.google.common.base.Objects.toStringHelper; import static com.google.common.base.Preconditions.checkNotNull; /** @@ -121,7 +122,7 @@ public class Header { return string().toString(); } - protected Objects.ToStringHelper string() { + protected MoreObjects.ToStringHelper string() { return toStringHelper(this).omitNullValues().add("signerAlgorithm", signerAlgorithm) .add("type", type); } diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java index 78cb402d08..ca2bd0817a 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java @@ -16,13 +16,14 @@ */ package org.jclouds.oauth.v2.domain; +import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import org.jclouds.domain.Credentials; import java.security.PrivateKey; +import static com.google.common.base.MoreObjects.toStringHelper; import static com.google.common.base.Objects.equal; -import static com.google.common.base.Objects.toStringHelper; import static com.google.common.base.Preconditions.checkNotNull; /** @@ -121,7 +122,7 @@ public class OAuthCredentials extends Credentials { return string().toString(); } - protected Objects.ToStringHelper string() { + protected MoreObjects.ToStringHelper string() { return toStringHelper(this).omitNullValues().add("identity", identity) .add("credential", credential != null ? credential.hashCode() : null).add("privateKey", privateKey.hashCode()); diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java index a18a7eb6e3..ff44d69775 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java @@ -16,12 +16,13 @@ */ package org.jclouds.oauth.v2.domain; +import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import java.beans.ConstructorProperties; +import static com.google.common.base.MoreObjects.toStringHelper; import static com.google.common.base.Objects.equal; -import static com.google.common.base.Objects.toStringHelper; import static com.google.common.base.Preconditions.checkNotNull; /** @@ -141,7 +142,7 @@ public class Token { return string().toString(); } - protected Objects.ToStringHelper string() { + protected MoreObjects.ToStringHelper string() { return toStringHelper(this).omitNullValues().add("accessToken", accessToken) .add("tokenType", tokenType).add("expiresIn", expiresIn); } 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 index 7d1a6a4438..71f3420a05 100644 --- 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 @@ -16,10 +16,11 @@ */ package org.jclouds.oauth.v2.domain; +import com.google.common.base.MoreObjects; import com.google.common.base.Objects; +import static com.google.common.base.MoreObjects.toStringHelper; import static com.google.common.base.Objects.equal; -import static com.google.common.base.Objects.toStringHelper; import static com.google.common.base.Preconditions.checkNotNull; /** @@ -122,7 +123,7 @@ public class TokenRequest { return string().toString(); } - protected Objects.ToStringHelper string() { + protected MoreObjects.ToStringHelper string() { return toStringHelper(this).omitNullValues().add("header", header) .add("claimSet", claimSet); } From 00d9edc1e6c1893fd2d3fdcb2600cba2287db36e Mon Sep 17 00:00:00 2001 From: Chris Custine Date: Thu, 31 Jul 2014 01:57:19 -0600 Subject: [PATCH 19/33] JCLOUDS-643: Fix Google and OAuth tests --- apis/oauth/pom.xml | 8 +++++++- .../test/java/org/jclouds/oauth/v2/OAuthTestUtils.java | 8 ++++++-- .../jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java | 4 ++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/apis/oauth/pom.xml b/apis/oauth/pom.xml index 31d34ac287..a157fde604 100644 --- a/apis/oauth/pom.xml +++ b/apis/oauth/pom.xml @@ -92,6 +92,12 @@ org.apache.maven.plugins maven-surefire-plugin + + default-test + + true + + integration integration-test @@ -105,7 +111,7 @@ ${test.oauth.endpoint} ${test.oauth.api-version} ${test.oauth.build-version} - ${test.jclouds.oauth.signature-or-mac-algorithm>} + ${test.jclouds.oauth.signature-or-mac-algorithm} ${test.jclouds.oauth.audience} ${test.jclouds.oauth.scopes} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java index 28879a98ce..7e27844e23 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java @@ -46,7 +46,7 @@ public class OAuthTestUtils { } } - public static String setCredentialFromPemFile(Properties overrides, String key) { + public static String setCredential(Properties overrides, String key) { String val = null; String credentialFromFile = null; String testKey = "test." + key; @@ -54,7 +54,11 @@ public class OAuthTestUtils { if (System.getProperties().containsKey(testKey)) { val = System.getProperty(testKey); } - checkNotNull(val, String.format("the property %s must be set (pem private key path)", testKey)); + checkNotNull(val, String.format("the property %s must be set (pem private key file path or private key as a string)", testKey)); + + if (val.startsWith("-----BEGIN")) { + return val; + } try { credentialFromFile = Files.toString(new File(val), Charsets.UTF_8); diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java index ee1149002b..ba1c616bcc 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java @@ -17,7 +17,7 @@ package org.jclouds.oauth.v2.internal; import static com.google.common.base.Preconditions.checkNotNull; -import static org.jclouds.oauth.v2.OAuthTestUtils.setCredentialFromPemFile; +import static org.jclouds.oauth.v2.OAuthTestUtils.setCredential; import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; import static org.jclouds.oauth.v2.config.OAuthProperties.SCOPES; import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; @@ -40,7 +40,7 @@ public class BaseOAuthApiLiveTest extends BaseApiLiveTest { @Override protected Properties setupProperties() { Properties props = super.setupProperties(); - setCredentialFromPemFile(props, "oauth.credential"); + setCredential(props, "oauth.credential"); checkNotNull(setIfTestSystemPropertyPresent(props, "oauth.endpoint"), "test.oauth.endpoint must be set"); checkNotNull(setIfTestSystemPropertyPresent(props, AUDIENCE), "test.jclouds.oauth.audience must be set"); setIfTestSystemPropertyPresent(props, SCOPES); From d728e0343a4a5be5ffcd5aa57ccc2805f2711f23 Mon Sep 17 00:00:00 2001 From: Chris Custine Date: Fri, 18 Jul 2014 12:53:48 -0600 Subject: [PATCH 20/33] JCLOUDS-633: Support passing bearer token directly for OAuth2 --- .../oauth/v2/config/CredentialType.java | 42 +++++++++++++++++++ .../jclouds/oauth/v2/config/OAuthModule.java | 41 ++++++++++++++++-- .../oauth/v2/config/OAuthProperties.java | 8 ++++ .../v2/filters/BearerTokenAuthenticator.java | 41 ++++++++++++++++++ .../v2/filters/OAuthAuthenticationFilter.java | 27 ++++++++++++ .../oauth/v2/filters/OAuthAuthenticator.java | 3 +- .../org/jclouds/oauth/v2/OAuthTestUtils.java | 12 ++++++ 7 files changed, 168 insertions(+), 6 deletions(-) create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/config/CredentialType.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenAuthenticator.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticationFilter.java diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/CredentialType.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/CredentialType.java new file mode 100644 index 0000000000..24a658b1fe --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/CredentialType.java @@ -0,0 +1,42 @@ +/* + * 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.Preconditions.checkNotNull; + +import com.google.common.base.CaseFormat; + +/** + * Decides what type of credentials createContext is supplied with. + */ +public enum CredentialType { + + BEARER_TOKEN_CREDENTIALS, + + SERVICE_ACCOUNT_CREDENTIALS; + + @Override + public String toString() { + return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, name()); + } + + public static CredentialType fromValue(String credentialType) { + return valueOf(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, checkNotNull(credentialType, + "credentialType"))); + } + +} 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 11fca2f982..1041c074bb 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 @@ -23,13 +23,20 @@ import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableMap; 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; 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.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.OAuthCredentialsSupplier; @@ -38,8 +45,6 @@ import org.jclouds.oauth.v2.json.ClaimSetTypeAdapter; import org.jclouds.oauth.v2.json.HeaderTypeAdapter; import org.jclouds.rest.internal.GeneratedHttpRequest; -import javax.inject.Named; -import javax.inject.Singleton; import java.lang.reflect.Type; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -56,8 +61,9 @@ public class OAuthModule extends AbstractModule { protected void configure() { bind(new TypeLiteral>() {}).to(SignOrProduceMacForToken.class); bind(new TypeLiteral>() {}).toInstance(ImmutableMap.of( - Header.class, new HeaderTypeAdapter(), - ClaimSet.class, new ClaimSetTypeAdapter())); + Header.class, new HeaderTypeAdapter(), + ClaimSet.class, new ClaimSetTypeAdapter())); + bind(CredentialType.class).toProvider(CredentialTypeFromPropertyOrDefault.class); bind(new TypeLiteral>() {}).to(OAuthCredentialsSupplier.class); bind(new TypeLiteral>() {}).to(BuildTokenRequest.class); bind(new TypeLiteral>() {}).to(FetchToken.class); @@ -83,4 +89,31 @@ public class OAuthModule extends AbstractModule { .from(getAccess)); } + @Singleton + public static class CredentialTypeFromPropertyOrDefault implements Provider { + @Inject(optional = true) + @Named(OAuthProperties.CREDENTIAL_TYPE) + String credentialType = CredentialType.SERVICE_ACCOUNT_CREDENTIALS.toString(); + + @Override + public CredentialType get() { + return CredentialType.fromValue(credentialType); + } + } + + @Provides + @Singleton + protected OAuthAuthenticationFilter authenticationFilterForCredentialType(CredentialType credentialType, + OAuthAuthenticator serviceAccountAuth, + BearerTokenAuthenticator bearerTokenAuth) { + switch (credentialType) { + case SERVICE_ACCOUNT_CREDENTIALS: + return serviceAccountAuth; + case BEARER_TOKEN_CREDENTIALS: + return bearerTokenAuth; + default: + throw new IllegalArgumentException("Unsupported credential type: " + credentialType); + } + } + } 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 7b1bf17fce..9394cad09c 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 @@ -40,4 +40,12 @@ public class OAuthProperties { * Optional list of comma-separated scopes to use when no OAuthScopes annotation is present. */ public static final String SCOPES = "jclouds.oauth.scopes"; + + /** + * Specify if credentials are id + private key or if you are reusing an oauth2 token. + * + * @see org.jclouds.oauth.v2.config.CredentialType + */ + public static final String CREDENTIAL_TYPE = "jclouds.oauth.credential-type"; + } 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 new file mode 100644 index 0000000000..779ba44095 --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenAuthenticator.java @@ -0,0 +1,41 @@ +/* + * 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 com.google.common.base.Supplier; +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; + +@Singleton +public class BearerTokenAuthenticator implements OAuthAuthenticationFilter { + private final Supplier creds; + + @Inject + BearerTokenAuthenticator(final 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(); + } +} 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 new file mode 100644 index 0000000000..e6e5714b85 --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticationFilter.java @@ -0,0 +1,27 @@ +/* + * 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 { + +} 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 e25bc201e1..c5c7b6f939 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 @@ -20,7 +20,6 @@ import com.google.common.base.Function; import com.google.common.cache.LoadingCache; import org.jclouds.http.HttpException; import org.jclouds.http.HttpRequest; -import org.jclouds.http.HttpRequestFilter; import org.jclouds.oauth.v2.domain.Token; import org.jclouds.oauth.v2.domain.TokenRequest; import org.jclouds.rest.internal.GeneratedHttpRequest; @@ -36,7 +35,7 @@ import static com.google.common.base.Preconditions.checkState; * TODO when we're able to use the OAuthAuthentication an this should be used automatically */ @Singleton -public class OAuthAuthenticator implements HttpRequestFilter { +public class OAuthAuthenticator implements OAuthAuthenticationFilter { private Function tokenRequestBuilder; private Function tokenFetcher; diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java index 7e27844e23..901cdfe347 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java @@ -19,6 +19,8 @@ package org.jclouds.oauth.v2; import com.google.common.base.Charsets; import com.google.common.base.Throwables; import com.google.common.io.Files; +import org.jclouds.oauth.v2.config.CredentialType; +import org.jclouds.oauth.v2.config.OAuthProperties; import java.io.File; import java.io.IOException; @@ -46,6 +48,16 @@ public class OAuthTestUtils { } } + public static Properties bearerTokenAuthProperties(Properties properties) { + properties = properties == null ? new Properties() : properties; + properties.put("oauth.identity", "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com"); + properties.put("oauth.credential", "1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M"); + properties.put("oauth.endpoint", "http://localhost:5000/o/oauth2/token"); + properties.put(AUDIENCE, "https://accounts.google.com/o/oauth2/token"); + properties.put(OAuthProperties.CREDENTIAL_TYPE, CredentialType.BEARER_TOKEN_CREDENTIALS.toString()); + return properties; + } + public static String setCredential(Properties overrides, String key) { String val = null; String credentialFromFile = null; From 52cf5555db9518d6b1d5777778d28c1716647395 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sun, 5 Oct 2014 11:03:30 -0700 Subject: [PATCH 21/33] Remove stale javadoc references to AsyncApi. --- apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApi.java | 2 -- .../main/java/org/jclouds/oauth/v2/config/Authentication.java | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) 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 12e8fcbb92..1b20734ac0 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 @@ -37,8 +37,6 @@ import org.jclouds.rest.annotations.Endpoint; * 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. - * - * @see OAuthAsyncApi */ @Endpoint(Authentication.class) public interface OAuthApi extends Closeable { diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authentication.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authentication.java index 4f1107a0b7..24f6851467 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authentication.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authentication.java @@ -26,7 +26,7 @@ import java.lang.annotation.Target; /** * Qualifies OAuth related resources, such as Endpoint. * - * @see org.jclouds.oauth.v2.OAuthAsyncApi + * @see org.jclouds.oauth.v2.OAuthApi */ @Retention(value = RetentionPolicy.RUNTIME) @Target(value = {ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD}) From f94d0caf3b1cda76b4e536fa048994943bc192bb Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Thu, 23 Oct 2014 20:11:39 -0700 Subject: [PATCH 22/33] Revert "JCLOUDS-653: Address Guava 18 deprecations" This reverts commit e2e288ee86d537d249c7e58c782a66b0201f2134. Many conflicts on account of lots of changes since the original commit. --- .../src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java | 4 ++-- .../src/main/java/org/jclouds/oauth/v2/domain/Header.java | 5 ++--- .../java/org/jclouds/oauth/v2/domain/OAuthCredentials.java | 5 ++--- .../src/main/java/org/jclouds/oauth/v2/domain/Token.java | 5 ++--- .../main/java/org/jclouds/oauth/v2/domain/TokenRequest.java | 5 ++--- 5 files changed, 10 insertions(+), 14 deletions(-) diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java index 214347410d..5c0b348d0f 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java @@ -26,9 +26,9 @@ import com.google.common.collect.Sets; import java.util.Map; import java.util.Set; -import static com.google.common.base.MoreObjects.ToStringHelper; -import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Objects.ToStringHelper; import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; 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 index baacc115d0..c230e1da4c 100644 --- 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 @@ -16,11 +16,10 @@ */ package org.jclouds.oauth.v2.domain; -import com.google.common.base.MoreObjects; import com.google.common.base.Objects; -import static com.google.common.base.MoreObjects.toStringHelper; import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; import static com.google.common.base.Preconditions.checkNotNull; /** @@ -122,7 +121,7 @@ public class Header { return string().toString(); } - protected MoreObjects.ToStringHelper string() { + protected Objects.ToStringHelper string() { return toStringHelper(this).omitNullValues().add("signerAlgorithm", signerAlgorithm) .add("type", type); } diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java index ca2bd0817a..78cb402d08 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java @@ -16,14 +16,13 @@ */ package org.jclouds.oauth.v2.domain; -import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import org.jclouds.domain.Credentials; import java.security.PrivateKey; -import static com.google.common.base.MoreObjects.toStringHelper; import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; import static com.google.common.base.Preconditions.checkNotNull; /** @@ -122,7 +121,7 @@ public class OAuthCredentials extends Credentials { return string().toString(); } - protected MoreObjects.ToStringHelper string() { + protected Objects.ToStringHelper string() { return toStringHelper(this).omitNullValues().add("identity", identity) .add("credential", credential != null ? credential.hashCode() : null).add("privateKey", privateKey.hashCode()); diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java index ff44d69775..a18a7eb6e3 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java @@ -16,13 +16,12 @@ */ package org.jclouds.oauth.v2.domain; -import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import java.beans.ConstructorProperties; -import static com.google.common.base.MoreObjects.toStringHelper; import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; import static com.google.common.base.Preconditions.checkNotNull; /** @@ -142,7 +141,7 @@ public class Token { return string().toString(); } - protected MoreObjects.ToStringHelper string() { + protected Objects.ToStringHelper string() { return toStringHelper(this).omitNullValues().add("accessToken", accessToken) .add("tokenType", tokenType).add("expiresIn", expiresIn); } 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 index 71f3420a05..7d1a6a4438 100644 --- 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 @@ -16,11 +16,10 @@ */ package org.jclouds.oauth.v2.domain; -import com.google.common.base.MoreObjects; import com.google.common.base.Objects; -import static com.google.common.base.MoreObjects.toStringHelper; import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; import static com.google.common.base.Preconditions.checkNotNull; /** @@ -123,7 +122,7 @@ public class TokenRequest { return string().toString(); } - protected MoreObjects.ToStringHelper string() { + protected Objects.ToStringHelper string() { return toStringHelper(this).omitNullValues().add("header", header) .add("claimSet", claimSet); } From 07d7a5a749ddc1e248d24ae544e1a1258a677ba6 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sat, 25 Oct 2014 15:23:30 -0700 Subject: [PATCH 23/33] JCLOUDS-750 At the cost of fiddling with type hierarchy adapters, remove lots of junk with google auto. --- apis/oauth/pom.xml | 11 ++ .../java/org/jclouds/oauth/v2/OAuthApi.java | 1 - .../jclouds/oauth/v2/OAuthApiMetadata.java | 10 +- .../jclouds/oauth/v2/config/OAuthModule.java | 48 ++--- .../oauth/v2/config/OAuthParserModule.java | 159 ++++++++++++++++ .../org/jclouds/oauth/v2/domain/ClaimSet.java | 173 ++---------------- .../org/jclouds/oauth/v2/domain/Header.java | 108 +---------- .../org/jclouds/oauth/v2/domain/Token.java | 138 ++------------ .../jclouds/oauth/v2/domain/TokenRequest.java | 116 +----------- .../oauth/v2/domain/TokenRequestFormat.java | 2 +- .../oauth/v2/filters/OAuthAuthenticator.java | 2 +- .../oauth/v2/functions/BuildTokenRequest.java | 33 ++-- .../v2/internal/SubtypeAdapterFactory.java | 42 +++++ .../oauth/v2/json/ClaimSetTypeAdapter.java | 59 ------ .../oauth/v2/json/HeaderTypeAdapter.java | 52 ------ .../oauth/v2/json/JWTTokenRequestFormat.java | 19 +- .../services/org.jclouds.apis.ApiMetadata | 18 -- .../org/jclouds/oauth/v2/OAuthTestUtils.java | 26 ++- .../oauth/v2/features/OAuthApiExpectTest.java | 99 ---------- .../oauth/v2/features/OAuthApiLiveTest.java | 10 +- .../oauth/v2/features/OAuthApiMockTest.java | 114 ++++++++++++ .../v2/internal/BaseOAuthApiExpectTest.java | 23 --- .../BaseOAuthAuthenticatedApiLiveTest.java | 13 +- ...xpectTest.java => BaseOAuthParseTest.java} | 12 +- .../v2/json/JWTTokenRequestFormatTest.java | 9 +- .../oauth/v2/parse/ParseTokenTest.java | 18 +- 26 files changed, 459 insertions(+), 856 deletions(-) create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthParserModule.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/internal/SubtypeAdapterFactory.java delete mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java delete mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/json/HeaderTypeAdapter.java delete mode 100644 apis/oauth/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata delete mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiExpectTest.java create mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiMockTest.java delete mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiExpectTest.java rename apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/{BaseOAuthExpectTest.java => BaseOAuthParseTest.java} (67%) diff --git a/apis/oauth/pom.xml b/apis/oauth/pom.xml index a157fde604..7c22dcb366 100644 --- a/apis/oauth/pom.xml +++ b/apis/oauth/pom.xml @@ -48,6 +48,12 @@ jclouds-core ${jclouds.version} + + com.google.auto.value + auto-value + 1.0-rc2 + provided + org.apache.jclouds jclouds-core @@ -61,6 +67,11 @@ ${jclouds.version} test + + com.squareup.okhttp + mockwebserver + test + ch.qos.logback logback-classic 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 1b20734ac0..4a12d8d1ed 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 @@ -57,5 +57,4 @@ public interface OAuthApi extends Closeable { @POST @Consumes(MediaType.APPLICATION_JSON) Token authenticate(@BinderParam(OAuthTokenBinder.class) TokenRequest tokenRequest) throws AuthorizationException; - } 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 index 3ef26e69c7..d946d702f5 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java @@ -22,16 +22,17 @@ import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGOR 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.oauth.v2.config.OAuthParserModule; import org.jclouds.rest.internal.BaseHttpApiMetadata; +import com.google.auto.service.AutoService; import com.google.common.collect.ImmutableSet; import com.google.inject.Module; -/** - * Implementation of {@link ApiMetadata} for OAuth 2 API - */ +@AutoService(ApiMetadata.class) public class OAuthApiMetadata extends BaseHttpApiMetadata { @Override @@ -64,7 +65,8 @@ public class OAuthApiMetadata extends BaseHttpApiMetadata { .documentation(URI.create("TODO")) .version("2") .defaultProperties(OAuthApiMetadata.defaultProperties()) - .defaultModules(ImmutableSet.>of(OAuthModule.class, OAuthHttpApiModule.class)); + .defaultModules(ImmutableSet + .>of(OAuthModule.class, OAuthParserModule.class, OAuthHttpApiModule.class)); } @Override 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 1041c074bb..788dac47cc 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,21 +16,10 @@ */ package org.jclouds.oauth.v2.config; -import com.google.common.base.Function; -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.collect.ImmutableMap; -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; -import org.jclouds.oauth.v2.domain.ClaimSet; -import org.jclouds.oauth.v2.domain.Header; +import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; + +import java.util.concurrent.TimeUnit; + import org.jclouds.oauth.v2.domain.OAuthCredentials; import org.jclouds.oauth.v2.domain.Token; import org.jclouds.oauth.v2.domain.TokenRequest; @@ -41,28 +30,25 @@ import org.jclouds.oauth.v2.functions.BuildTokenRequest; import org.jclouds.oauth.v2.functions.FetchToken; import org.jclouds.oauth.v2.functions.OAuthCredentialsSupplier; import org.jclouds.oauth.v2.functions.SignOrProduceMacForToken; -import org.jclouds.oauth.v2.json.ClaimSetTypeAdapter; -import org.jclouds.oauth.v2.json.HeaderTypeAdapter; import org.jclouds.rest.internal.GeneratedHttpRequest; -import java.lang.reflect.Type; -import java.util.Map; -import java.util.concurrent.TimeUnit; +import com.google.common.base.Function; +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.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; -import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; - -/** - * Base OAuth module - */ public class OAuthModule extends AbstractModule { - - @Override - protected void configure() { + @Override protected void configure() { bind(new TypeLiteral>() {}).to(SignOrProduceMacForToken.class); - bind(new TypeLiteral>() {}).toInstance(ImmutableMap.of( - Header.class, new HeaderTypeAdapter(), - ClaimSet.class, new ClaimSetTypeAdapter())); bind(CredentialType.class).toProvider(CredentialTypeFromPropertyOrDefault.class); bind(new TypeLiteral>() {}).to(OAuthCredentialsSupplier.class); bind(new TypeLiteral>() {}).to(BuildTokenRequest.class); diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthParserModule.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthParserModule.java new file mode 100644 index 0000000000..4768e6b644 --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthParserModule.java @@ -0,0 +1,159 @@ +/* + * 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.io.IOException; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import javax.inject.Singleton; + +import org.jclouds.oauth.v2.domain.ClaimSet; +import org.jclouds.oauth.v2.domain.Header; +import org.jclouds.oauth.v2.domain.Token; + +import com.google.common.collect.ImmutableSet; +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import com.google.inject.AbstractModule; +import com.google.inject.Provides; + +/** Configures type adapter factories for {@link Header}, {@link ClaimSet}, and {@link Token}. */ +public final class OAuthParserModule extends AbstractModule { + @Override protected void configure() { + } + + // TODO: change jclouds core to use collaborative set bindings + @Provides @Singleton public Set typeAdapterFactories() { + return ImmutableSet + .of(new HeaderTypeAdapter(), new ClaimSetTypeAdapter(), new TokenAdapter()); + } + + private static final class HeaderTypeAdapter extends SubtypeAdapterFactory

{ + HeaderTypeAdapter() { + super(Header.class); + } + + @Override public void write(JsonWriter out, Header value) throws IOException { + out.beginObject(); + out.name("alg"); + out.value(value.signerAlgorithm()); + out.name("typ"); + out.value(value.type()); + out.endObject(); + } + + @Override public Header read(JsonReader in) throws IOException { + in.beginObject(); + in.nextName(); + String signerAlgorithm = in.nextString(); + in.nextName(); + String type = in.nextString(); + in.endObject(); + return Header.create(signerAlgorithm, type); + } + } + + private static final class ClaimSetTypeAdapter extends SubtypeAdapterFactory { + ClaimSetTypeAdapter() { + super(ClaimSet.class); + } + + @Override public void write(JsonWriter out, ClaimSet value) throws IOException { + out.beginObject(); + for (Map.Entry entry : value.claims().entrySet()) { + out.name(entry.getKey()); + out.value(entry.getValue()); + } + out.name("exp"); + out.value(value.expirationTime()); + out.name("iat"); + out.value(value.emissionTime()); + out.endObject(); + } + + @Override public ClaimSet read(JsonReader in) throws IOException { + Map claims = new LinkedHashMap(); + in.beginObject(); + while (in.hasNext()) { + claims.put(in.nextName(), in.nextString()); + } + in.endObject(); + return ClaimSet.create(0, 0, Collections.unmodifiableMap(claims)); + } + } + + /** OAuth is used in apis that may not default to snake case. Explicity control case format. */ + private static final class TokenAdapter extends SubtypeAdapterFactory { + TokenAdapter() { + super(Token.class); + } + + @Override public void write(JsonWriter out, Token value) throws IOException { + out.beginObject(); + out.name("access_token"); + out.value(value.accessToken()); + out.name("token_type"); + out.value(value.tokenType()); + out.name("expires_in"); + out.value(value.expiresIn()); + out.endObject(); + } + + @Override public Token read(JsonReader in) throws IOException { + String accessToken = null; + String tokenType = null; + int expiresIn = 0; + in.beginObject(); + while (in.hasNext()) { + String name = in.nextName(); + if (name.equals("access_token")) { + accessToken = in.nextString(); + } else if (name.equals("token_type")) { + tokenType = in.nextString(); + } else if (name.equals("expires_in")) { + expiresIn = in.nextInt(); + } else { + in.skipValue(); + } + } + in.endObject(); + return Token.create(accessToken, tokenType, expiresIn); + } + } + + private abstract static class SubtypeAdapterFactory extends TypeAdapter implements TypeAdapterFactory { + private final Class baseClass; + + private SubtypeAdapterFactory(Class baseClass) { + this.baseClass = baseClass; + } + + @Override public TypeAdapter create(Gson gson, TypeToken typeToken) { + if (!(baseClass.isAssignableFrom(typeToken.getRawType()))) { + return null; + } + return (TypeAdapter) this; + } + } +} diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java index 5c0b348d0f..e265e905db 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java @@ -16,176 +16,27 @@ */ package org.jclouds.oauth.v2.domain; -import com.google.common.base.Objects; -import com.google.common.base.Splitter; -import com.google.common.collect.ForwardingMap; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Sets; - import java.util.Map; -import java.util.Set; -import static com.google.common.base.Objects.ToStringHelper; -import static com.google.common.base.Objects.equal; -import static com.google.common.base.Objects.toStringHelper; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; +import com.google.auto.value.AutoValue; /** - * The claimset for the token. + * The claimset for the {@linkplain Token}. * - * @see doc + * @see doc */ -public class ClaimSet extends ForwardingMap { +@AutoValue +public abstract class ClaimSet { - public static Builder builder() { - return new Builder(); - } + /** The emission time, in seconds since the epoch. */ + public abstract long emissionTime(); - public Builder toBuilder() { - return builder().fromClaimSet(this); - } + /** The expiration time, in seconds since the emission time. */ + public abstract long expirationTime(); - public static class Builder { + public abstract Map claims(); - private Set requiredClaims; - private ImmutableMap.Builder claims = new ImmutableMap.Builder(); - private long emissionTime; - private long expirationTime; - - public Builder() { - this(ImmutableSet.of()); - } - - /** - * Constructor that allows to predefine a mandatory set of claims as a comma-separated string, e.g, "iss,iat". - */ - public Builder(String commaSeparatedRequiredClaims) { - this(ImmutableSet.copyOf(Splitter.on(",").split(checkNotNull(commaSeparatedRequiredClaims)))); - } - - /** - * Constructor that allows to predefine a mandatory set of claims as a set of strings. - */ - public Builder(Set requiredClaims) { - this.requiredClaims = ImmutableSet.copyOf(checkNotNull(requiredClaims)); - } - - /** - * Adds a Claim, i.e. key/value pair, e.g., "scope":"all_permissions". - */ - public Builder addClaim(String name, String value) { - claims.put(checkNotNull(name), checkNotNull(value, "value of %s", name)); - return this; - } - - /** - * @see ClaimSet#getEmissionTime() - */ - public Builder emissionTime(long emmissionTime) { - this.emissionTime = emmissionTime; - return this; - } - - /** - * @see ClaimSet#getExpirationTime() - */ - public Builder expirationTime(long expirationTime) { - this.expirationTime = expirationTime; - return this; - } - - /** - * Adds a map containing multiple claims - */ - public Builder addAllClaims(Map claims) { - this.claims.putAll(checkNotNull(claims)); - return this; - } - - public ClaimSet build() { - Map claimsMap = claims.build(); - checkState(Sets.intersection(claimsMap.keySet(), requiredClaims).size() == requiredClaims.size(), - "not all required claims were present"); - if (expirationTime == 0) { - expirationTime = emissionTime + 3600; - } - return new ClaimSet(claimsMap, emissionTime, expirationTime); - } - - public Builder fromClaimSet(ClaimSet claimSet) { - return new Builder().addAllClaims(claimSet.claims).expirationTime(expirationTime).emissionTime(emissionTime); - } - } - - private final Map claims; - private final long emissionTime; - private final long expirationTime; - - private ClaimSet(Map claims, long emissionTime, long expirationTime) { - this.claims = claims; - this.emissionTime = emissionTime; - this.expirationTime = expirationTime; - } - - /** - * The emission time, in seconds since the epoch. - */ - public long getEmissionTime() { - return emissionTime; - } - - /** - * The expiration time, in seconds since the emission time. - */ - public long getExpirationTime() { - return expirationTime; - } - - /** - * @returns the claims. - */ - @Override - protected Map delegate() { - return claims; - } - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - return Objects.hashCode(claims); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - ClaimSet other = (ClaimSet) obj; - return equal(claims, other.claims); - } - - /** - * {@inheritDoc} - */ - @Override - public String toString() { - return string().toString(); - } - - protected ToStringHelper string() { - return toStringHelper(this).omitNullValues().add("claims", claims) - .add("emissionTime", emissionTime).add("expirationTIme", expirationTime); + public static ClaimSet create(long emissionTime, long expirationTime, Map claims) { + return new AutoValue_ClaimSet(emissionTime, expirationTime, claims); } } 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 index c230e1da4c..9146824654 100644 --- 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 @@ -16,113 +16,23 @@ */ package org.jclouds.oauth.v2.domain; -import com.google.common.base.Objects; - -import static com.google.common.base.Objects.equal; -import static com.google.common.base.Objects.toStringHelper; -import static com.google.common.base.Preconditions.checkNotNull; +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 doc */ -public class Header { +@AutoValue +public abstract class Header { - public static Builder builder() { - return new Builder(); - } + /** The name of the algorithm used to compute the signature, e.g., {@code RS256}. */ + public abstract String signerAlgorithm(); - public Builder toBuilder() { - return builder().fromHeader(this); - } + /** The type of the token, e.g., {@code JWT}. */ + public abstract String type(); - public static class Builder { - - private String signerAlgorithm; - private String type; - - /** - * @see Header#getSignerAlgorithm() - */ - public Builder signerAlgorithm(String signerAlgorithm) { - this.signerAlgorithm = checkNotNull(signerAlgorithm); - return this; - } - - /** - * @see Header#getType() - */ - public Builder type(String type) { - this.type = checkNotNull(type); - return this; - } - - public Header build() { - return new Header(signerAlgorithm, type); - } - - public Builder fromHeader(Header header) { - return new Builder().signerAlgorithm(header.signerAlgorithm).type(header.type); - } - } - - private final String signerAlgorithm; - private final String type; - - protected Header(String signerAlgorithm, String type) { - this.signerAlgorithm = checkNotNull(signerAlgorithm); - this.type = checkNotNull(type); - } - - /** - * The name of the algorithm used to compute the signature, e.g., "RS256" - */ - public String getSignerAlgorithm() { - return signerAlgorithm; - } - - /** - * The type of the token, e.g., "JWT" - */ - public String getType() { - return type; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Header other = (Header) obj; - return equal(this.signerAlgorithm, other.signerAlgorithm) && equal(this.type, - other.type); - } - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - return Objects.hashCode(signerAlgorithm, type); - } - - /** - * {@inheritDoc} - */ - @Override - public String toString() { - return string().toString(); - } - - protected Objects.ToStringHelper string() { - return toStringHelper(this).omitNullValues().add("signerAlgorithm", signerAlgorithm) - .add("type", type); + public static Header create(String signerAlgorithm, String type){ + return new AutoValue_Header(signerAlgorithm, type); } } diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java index a18a7eb6e3..cf7ce577f1 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java @@ -16,134 +16,24 @@ */ package org.jclouds.oauth.v2.domain; -import com.google.common.base.Objects; - -import java.beans.ConstructorProperties; - -import static com.google.common.base.Objects.equal; -import static com.google.common.base.Objects.toStringHelper; -import static com.google.common.base.Preconditions.checkNotNull; +import com.google.auto.value.AutoValue; /** * The oauth token, obtained upon a successful token request and ready to embed in requests. */ -public class Token { +@AutoValue +public abstract class Token { + /** The access token obtained from the OAuth server. */ + public abstract String accessToken(); - public static Builder builder() { - return new Builder(); + /** The type of the token, e.g., {@code Bearer}. */ + public abstract String tokenType(); + + /** In how many seconds this token expires. */ + public abstract long expiresIn(); + + public static Token + create(String accessToken, String tokenType, long expiresIn) { + return new AutoValue_Token(accessToken, tokenType, expiresIn); } - - public Builder toBuilder() { - return builder().fromToken(this); - } - - public static class Builder { - - private String accessToken; - private String tokenType; - private long expiresIn; - - /** - * @see Token#getAccessToken() - */ - public Builder accessToken(String accessToken) { - this.accessToken = checkNotNull(accessToken); - return this; - } - - /** - * @see Token#getTokenType() - */ - public Builder tokenType(String tokenType) { - this.tokenType = checkNotNull(tokenType); - return this; - } - - /** - * @see Token#getExpiresIn() - */ - public Builder expiresIn(long expiresIn) { - this.expiresIn = expiresIn; - return this; - } - - public Token build() { - return new Token(accessToken, tokenType, expiresIn); - } - - public Builder fromToken(Token token) { - return new Builder().accessToken(token.accessToken).tokenType(token.tokenType).expiresIn(token.expiresIn); - } - } - - private final String accessToken; - private final String tokenType; - private final long expiresIn; - - @ConstructorProperties({"access_token", "token_type", "expires_in"}) - protected Token(String accessToken, String tokenType, long expiresIn) { - this.accessToken = accessToken; - this.tokenType = tokenType; - this.expiresIn = expiresIn; - } - - /** - * The access token obtained from the OAuth server. - */ - public String getAccessToken() { - return accessToken; - } - - /** - * The type of the token, e.g., "Bearer" - */ - public String getTokenType() { - return tokenType; - } - - /** - * In how many seconds this token expires. - */ - public long getExpiresIn() { - return expiresIn; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Token other = (Token) obj; - return equal(this.accessToken, other.accessToken) && equal(this.tokenType, - other.tokenType) && equal(this.expiresIn, - other.expiresIn); - } - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - return Objects.hashCode(accessToken, tokenType, expiresIn); - } - - /** - * {@inheritDoc} - */ - @Override - public String toString() { - return string().toString(); - } - - protected Objects.ToStringHelper string() { - return toStringHelper(this).omitNullValues().add("accessToken", accessToken) - .add("tokenType", tokenType).add("expiresIn", expiresIn); - } - } 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 index 7d1a6a4438..a0154bf4b1 100644 --- 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 @@ -16,116 +16,14 @@ */ package org.jclouds.oauth.v2.domain; -import com.google.common.base.Objects; +import com.google.auto.value.AutoValue; -import static com.google.common.base.Objects.equal; -import static com.google.common.base.Objects.toStringHelper; -import static com.google.common.base.Preconditions.checkNotNull; +@AutoValue +public abstract class TokenRequest { + public abstract Header header(); + public abstract ClaimSet claimSet(); -/** - * A complete token request. - */ -public class TokenRequest { - - public static Builder builder() { - return new Builder(); + public static TokenRequest create(Header header, ClaimSet claimSet) { + return new AutoValue_TokenRequest(header, claimSet); } - - public Builder toBuilder() { - return builder().fromTokenRequest(this); - } - - public static class Builder { - private Header header; - private ClaimSet claimSet; - - /** - * @see TokenRequest#getClaimSet() - */ - public Builder header(Header header) { - this.header = header; - return this; - } - - /** - * @see TokenRequest#getHeader() - */ - public Builder claimSet(ClaimSet claimSet) { - this.claimSet = claimSet; - return this; - } - - public TokenRequest build() { - return new TokenRequest(header, claimSet); - } - - public Builder fromTokenRequest(TokenRequest tokeRequest) { - return new Builder().header(tokeRequest.header).claimSet(tokeRequest.claimSet); - } - } - - private final Header header; - private final ClaimSet claimSet; - - public TokenRequest(Header header, ClaimSet claimSet) { - this.header = checkNotNull(header); - this.claimSet = checkNotNull(claimSet); - } - - /** - * The header of this token request. - * - * @see Header - */ - public Header getHeader() { - return header; - } - - /** - * The claim set of this token request. - * - * @see ClaimSet - */ - public ClaimSet getClaimSet() { - return claimSet; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - TokenRequest other = (TokenRequest) obj; - return equal(this.header, other.header) && equal(this.claimSet, - other.claimSet); - } - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - return Objects.hashCode(header, claimSet); - } - - /** - * {@inheritDoc} - */ - @Override - public String toString() { - return string().toString(); - } - - protected Objects.ToStringHelper string() { - return toStringHelper(this).omitNullValues().add("header", header) - .add("claimSet", claimSet); - } - - } 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 index f4b80c177f..7099592e01 100644 --- 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 @@ -36,7 +36,7 @@ public interface TokenRequestFormat { /** * The name of the type of the token request, e.g., "JWT" */ - String getTypeName(); + String type(); /** * The claims that must be present in the token request for it to be valid. 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 c5c7b6f939..40fc0cfd37 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 @@ -54,7 +54,7 @@ public class OAuthAuthenticator implements OAuthAuthenticationFilter { TokenRequest tokenRequest = tokenRequestBuilder.apply(generatedHttpRequest); Token token = tokenFetcher.apply(tokenRequest); return request.toBuilder().addHeader("Authorization", String.format("%s %s", - token.getTokenType(), token.getAccessToken())).build(); + 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 7b869dcfc0..664dcab6ea 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 @@ -22,6 +22,8 @@ import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; import static org.jclouds.oauth.v2.config.OAuthProperties.SCOPES; import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; +import java.util.Collections; +import java.util.LinkedHashMap; import java.util.Map; import javax.inject.Singleton; @@ -38,7 +40,6 @@ 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.ImmutableMap; import com.google.common.reflect.Invokable; import com.google.inject.Inject; import com.google.inject.name.Named; @@ -61,7 +62,7 @@ public class BuildTokenRequest implements Function additionalClaims = ImmutableMap.of(); + protected Map additionalClaims = Collections.emptyMap(); @Inject(optional = true) @Named(SCOPES) @@ -93,24 +94,20 @@ public class BuildTokenRequest implements Function claims = new LinkedHashMap(); + claims.put("iss", credentialsSupplier.get().identity); + claims.put("scope", getOAuthScopes(request)); + claims.put("aud", assertionTargetDescription); + claims.putAll(additionalClaims); - return new TokenRequest.Builder() - .header(header) - .claimSet(claimSet) - .build(); + checkState(claims.keySet().containsAll(tokenRequestFormat.requiredClaims()), + "not all required claims were present"); + + ClaimSet claimSet = ClaimSet.create(now, now + tokenDuration, Collections.unmodifiableMap(claims)); + + return TokenRequest.create(header, claimSet); } protected String getOAuthScopes(GeneratedHttpRequest request) { 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 new file mode 100644 index 0000000000..f09bea6376 --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/internal/SubtypeAdapterFactory.java @@ -0,0 +1,42 @@ +/* + * 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/main/java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java deleted file mode 100644 index 62b3a26991..0000000000 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jclouds.oauth.v2.json; - -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import org.jclouds.oauth.v2.domain.ClaimSet; - -import java.io.IOException; -import java.util.Map; - -/** - * JSON TypeAdapter for the ClaimSet type. Pull the claims maps to the root level and adds two properties for the - * expiration time and issuing time. - */ -public class ClaimSetTypeAdapter extends TypeAdapter { - - @Override - public void write(JsonWriter out, ClaimSet value) throws IOException { - out.beginObject(); - for (Map.Entry entry : value.entrySet()) { - out.name(entry.getKey()); - out.value(entry.getValue()); - } - out.name("exp"); - out.value(value.getExpirationTime()); - out.name("iat"); - out.value(value.getEmissionTime()); - out.endObject(); - } - - @Override - public ClaimSet read(JsonReader in) throws IOException { - ClaimSet.Builder builder = new ClaimSet.Builder(); - in.beginObject(); - while (in.hasNext()) { - String claimName = in.nextName(); - String claimValue = in.nextString(); - builder.addClaim(claimName, claimValue); - } - in.endObject(); - return builder.build(); - } -} diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/HeaderTypeAdapter.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/HeaderTypeAdapter.java deleted file mode 100644 index f911a54752..0000000000 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/HeaderTypeAdapter.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jclouds.oauth.v2.json; - -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import org.jclouds.oauth.v2.domain.Header; - -import java.io.IOException; - -/** - * JSON TypeAdapter for the Header type. Simply transforms the field names. - */ -public class HeaderTypeAdapter extends TypeAdapter
{ - - @Override - public void write(JsonWriter out, Header value) throws IOException { - out.beginObject(); - out.name("alg"); - out.value(value.getSignerAlgorithm()); - out.name("typ"); - out.value(value.getType()); - out.endObject(); - } - - @Override - public Header read(JsonReader in) throws IOException { - Header.Builder builder = new Header.Builder(); - in.beginObject(); - in.nextName(); - builder.signerAlgorithm(in.nextString()); - in.nextName(); - builder.type(in.nextString()); - in.endObject(); - return builder.build(); - } -} 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/json/JWTTokenRequestFormat.java index 265cb26075..41d98048c8 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java @@ -24,7 +24,6 @@ import static org.jclouds.io.Payloads.newUrlEncodedFormPayload; import java.util.Set; import javax.inject.Inject; -import javax.inject.Singleton; import org.jclouds.http.HttpRequest; import org.jclouds.io.Payload; @@ -45,7 +44,6 @@ import com.google.common.collect.ImmutableSet; * https://developers.google.com/accounts/docs/OAuth2ServiceAccount *

*/ -@Singleton public class JWTTokenRequestFormat implements TokenRequestFormat { private static final String ASSERTION_FORM_PARAM = "assertion"; @@ -55,18 +53,15 @@ public class JWTTokenRequestFormat implements TokenRequestFormat { private final Function signer; private final Json json; - @Inject - public JWTTokenRequestFormat(Function signer, Json json) { + @Inject JWTTokenRequestFormat(Function signer, Json json) { this.signer = signer; this.json = json; } - @SuppressWarnings("unchecked") - @Override - public R formatRequest(R request, TokenRequest tokenRequest) { + @Override public R formatRequest(R request, TokenRequest tokenRequest) { - String encodedHeader = json.toJson(tokenRequest.getHeader()); - String encodedClaimSet = json.toJson(tokenRequest.getClaimSet()); + 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)); @@ -83,13 +78,11 @@ public class JWTTokenRequestFormat implements TokenRequestFormat { return (R) request.toBuilder().payload(payload).build(); } - @Override - public String getTypeName() { + @Override public String type() { return "JWT"; } - @Override - public Set requiredClaims() { + @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/resources/META-INF/services/org.jclouds.apis.ApiMetadata b/apis/oauth/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata deleted file mode 100644 index d7064de104..0000000000 --- a/apis/oauth/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata +++ /dev/null @@ -1,18 +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. -# - -org.jclouds.oauth.v2.OAuthApiMetadata diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java index 901cdfe347..438d6244c8 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java @@ -16,35 +16,33 @@ */ package org.jclouds.oauth.v2; -import com.google.common.base.Charsets; -import com.google.common.base.Throwables; -import com.google.common.io.Files; -import org.jclouds.oauth.v2.config.CredentialType; -import org.jclouds.oauth.v2.config.OAuthProperties; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Throwables.propagate; +import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; +import static org.jclouds.util.Strings2.toStringAndClose; import java.io.File; import java.io.IOException; import java.util.Properties; -import static com.google.common.base.Preconditions.checkNotNull; -import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; +import org.jclouds.oauth.v2.config.CredentialType; +import org.jclouds.oauth.v2.config.OAuthProperties; + +import com.google.common.base.Charsets; +import com.google.common.io.Files; -/** - * Utils for OAuth tests. - */ public class OAuthTestUtils { public static Properties defaultProperties(Properties properties) { try { properties = properties == null ? new Properties() : properties; properties.put("oauth.identity", "foo"); - properties.put("oauth.credential", - Files.asCharSource(new File("src/test/resources/testpk.pem"), Charsets.UTF_8).read()); + properties.put("oauth.credential", toStringAndClose(OAuthTestUtils.class.getResourceAsStream("/testpk.pem"))); properties.put("oauth.endpoint", "http://localhost:5000/o/oauth2/token"); properties.put(AUDIENCE, "https://accounts.google.com/o/oauth2/token"); return properties; } catch (IOException e) { - throw Throwables.propagate(e); + throw propagate(e); } } @@ -75,7 +73,7 @@ public class OAuthTestUtils { try { credentialFromFile = Files.toString(new File(val), Charsets.UTF_8); } catch (IOException e) { - throw Throwables.propagate(e); + throw propagate(e); } overrides.setProperty(key, credentialFromFile); return credentialFromFile; diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiExpectTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiExpectTest.java deleted file mode 100644 index 2008e5dddd..0000000000 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiExpectTest.java +++ /dev/null @@ -1,99 +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.features; - -import static com.google.common.base.Charsets.UTF_8; -import static com.google.common.io.BaseEncoding.base64Url; -import static org.testng.Assert.assertEquals; - -import java.net.URI; -import java.util.Properties; - -import javax.ws.rs.core.MediaType; - -import org.jclouds.http.HttpRequest; -import org.jclouds.http.HttpResponse; -import org.jclouds.oauth.v2.OAuthApi; -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.Token; -import org.jclouds.oauth.v2.domain.TokenRequest; -import org.jclouds.oauth.v2.internal.BaseOAuthApiExpectTest; -import org.testng.annotations.Test; - -/** - * Tests that a token requess is well formed. - */ -@Test(groups = "unit") -public class OAuthApiExpectTest extends BaseOAuthApiExpectTest { - - private static final String header = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}"; - - private static final String claims = "{\"iss\":\"761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer" + - ".gserviceaccount.com\"," + - "\"scope\":\"https://www.googleapis.com/auth/prediction\",\"aud\":\"https://accounts.google" + - ".com/o/oauth2/token\",\"exp\":1328573381,\"iat\":1328569781}"; - - private static final Token TOKEN = new Token.Builder().accessToken - ("1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M").tokenType("Bearer").expiresIn(3600).build(); - - private static final ClaimSet CLAIM_SET = new ClaimSet.Builder().addClaim("iss", - "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer" + - ".gserviceaccount.com") - .addClaim("scope", "https://www.googleapis.com/auth/prediction") - .addClaim("aud", "https://accounts.google.com/o/oauth2/token") - .expirationTime(1328573381) - .emissionTime(1328569781).build(); - - private static final Header HEADER = new Header.Builder().signerAlgorithm("RS256").type("JWT").build(); - - private static final String URL_ENCODED_TOKEN_REQUEST = - "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&" + - // Base64 Encoded Header - "assertion=" + base64Url().omitPadding().encode(header.getBytes(UTF_8)) + "." + - // Base64 Encoded Claims - base64Url().omitPadding().encode(claims.getBytes(UTF_8)) + "." + - // Base64 encoded {header}.{claims} signature (using SHA256) - "W2Lesr_98AzVYiMbzxFqmwcOjpIWlwqkC6pNn1fXND9oSDNNnFhy-AAR6DKH-x9ZmxbY80" + - "R5fH-OCeWumXlVgceKN8Z2SmgQsu8ElTpypQA54j_5j8vUImJ5hsOUYPeyF1U2BUzZ3L5g" + - "03PXBA0YWwRU9E1ChH28dQBYuGiUmYw"; - - private static final HttpRequest TOKEN_REQUEST = HttpRequest.builder() - .method("POST") - .endpoint(URI.create("http://localhost:5000/o/oauth2/token")) - .addHeader("Accept", MediaType.APPLICATION_JSON) - .payload(payloadFromStringWithContentType(URL_ENCODED_TOKEN_REQUEST, "application/x-www-form-urlencoded")) - .build(); - - private static final HttpResponse TOKEN_RESPONSE = HttpResponse.builder().statusCode(200).payload( - payloadFromString("{\n" + - " \"access_token\" : \"1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M\",\n" + - " \"token_type\" : \"Bearer\",\n" + - " \"expires_in\" : 3600\n" + - "}")).build(); - - @Override - protected Properties setupProperties() { - return OAuthTestUtils.defaultProperties(super.setupProperties()); - } - - public void testGenerateJWTRequest() { - OAuthApi api = requestSendsResponse(TOKEN_REQUEST, TOKEN_RESPONSE); - assertEquals(api.authenticate(new TokenRequest(HEADER, CLAIM_SET)), TOKEN); - } -} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java index 4ac59508a4..5b1e0e6215 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java @@ -34,6 +34,8 @@ import org.jclouds.oauth.v2.domain.TokenRequest; import org.jclouds.oauth.v2.internal.BaseOAuthApiLiveTest; import org.testng.annotations.Test; +import com.google.common.collect.ImmutableMap; + /** * A live test for authentication. Requires the following properties to be set: * - test.oauth.endpoint @@ -62,17 +64,17 @@ public class OAuthApiLiveTest extends BaseOAuthApiLiveTest { checkState(OAuthConstants.OAUTH_ALGORITHM_NAMES_TO_SIGNATURE_ALGORITHM_NAMES.containsKey(signatureAlgorithm) , String.format("Algorithm not supported: " + signatureAlgorithm)); - Header header = Header.builder().signerAlgorithm(signatureAlgorithm).type("JWT").build(); + Header header = Header.create(signatureAlgorithm, "JWT"); String scopes = getMandatoryProperty(properties, SCOPES); String audience = getMandatoryProperty(properties, AUDIENCE); long now = nowInSeconds(); - ClaimSet claimSet = ClaimSet.builder().addClaim("aud", audience).addClaim("scope", scopes).addClaim("iss", - identity).emissionTime(now).expirationTime(now + 3600).build(); + ClaimSet claimSet = ClaimSet.create(now, now + 3600, + ImmutableMap.of("aud", audience, "scope", scopes, "iss", identity)); - TokenRequest tokenRequest = TokenRequest.builder().header(header).claimSet(claimSet).build(); + TokenRequest tokenRequest = TokenRequest.create(header, claimSet); Token token = api.authenticate(tokenRequest); assertNotNull(token, "no token when authenticating " + tokenRequest); diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiMockTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiMockTest.java new file mode 100644 index 0000000000..95cc5375be --- /dev/null +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiMockTest.java @@ -0,0 +1,114 @@ +/* + * 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.features; + +import static com.google.common.base.Charsets.UTF_8; +import static com.google.common.io.BaseEncoding.base64Url; +import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.jclouds.Constants.PROPERTY_MAX_RETRIES; +import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; +import static org.jclouds.util.Strings2.toStringAndClose; +import static org.testng.Assert.assertEquals; + +import java.io.IOException; +import java.net.URL; +import java.util.Properties; + +import org.jclouds.ContextBuilder; +import org.jclouds.concurrent.config.ExecutorServiceModule; +import org.jclouds.oauth.v2.OAuthApi; +import org.jclouds.oauth.v2.OAuthApiMetadata; +import org.jclouds.oauth.v2.OAuthTestUtils; +import org.jclouds.oauth.v2.domain.ClaimSet; +import org.jclouds.oauth.v2.domain.Header; +import org.jclouds.oauth.v2.domain.Token; +import org.jclouds.oauth.v2.domain.TokenRequest; +import org.testng.annotations.Test; + +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.io.BaseEncoding; +import com.google.inject.Module; +import com.squareup.okhttp.mockwebserver.MockResponse; +import com.squareup.okhttp.mockwebserver.MockWebServer; +import com.squareup.okhttp.mockwebserver.RecordedRequest; + +@Test(groups = "unit", testName = "OAuthApiMockTest") +public class OAuthApiMockTest { + + private static final String header = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}"; + + private static final String claims = "{\"iss\":\"761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer" + + ".gserviceaccount.com\"," + + "\"scope\":\"https://www.googleapis.com/auth/prediction\",\"aud\":\"https://accounts.google" + + ".com/o/oauth2/token\",\"exp\":1328573381,\"iat\":1328569781}"; + + private static final Token TOKEN = Token.create("1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M", "Bearer", 3600); + + private static final ClaimSet CLAIM_SET = ClaimSet.create(1328569781, 1328573381, ImmutableMap + .of("iss", "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com", "scope", + "https://www.googleapis.com/auth/prediction", "aud", "https://accounts.google.com/o/oauth2/token")); + + private static final Header HEADER = Header.create("RS256", "JWT"); + + public void testGenerateJWTRequest() throws Exception { + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setBody("{\n" + + " \"access_token\" : \"1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M\",\n" + + " \"token_type\" : \"Bearer\",\n" + + " \"expires_in\" : 3600\n" + + "}")); + server.play(); + + OAuthApi api = api(server.getUrl("/")); + + assertEquals(api.authenticate(TokenRequest.create(HEADER, CLAIM_SET)), TOKEN); + + RecordedRequest request = server.takeRequest(); + assertEquals(request.getMethod(), "POST"); + assertEquals(request.getHeader("Accept"), APPLICATION_JSON); + assertEquals(request.getHeader("Content-Type"), "application/x-www-form-urlencoded"); + + assertEquals(new String(request.getBody(), UTF_8), // + "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&" + + // Base64 Encoded Header + "assertion=" + + Joiner.on('.').join(encoding.encode(header.getBytes(UTF_8)), encoding.encode(claims.getBytes(UTF_8)), + // Base64 encoded {header}.{claims} signature (using SHA256) + "W2Lesr_98AzVYiMbzxFqmwcOjpIWlwqkC6pNn1fXND9oSDNNnFhy-AAR6DKH-x9ZmxbY80" + + "R5fH-OCeWumXlVgceKN8Z2SmgQsu8ElTpypQA54j_5j8vUImJ5hsOUYPeyF1U2BUzZ3L5g" + + "03PXBA0YWwRU9E1ChH28dQBYuGiUmYw")); + + } + + private final BaseEncoding encoding = base64Url().omitPadding(); + + private OAuthApi api(URL url) throws IOException { + Properties overrides = new Properties(); + overrides.put(AUDIENCE, "https://accounts.google.com/o/oauth2/token"); + overrides.put(PROPERTY_MAX_RETRIES, "1"); + + return ContextBuilder.newBuilder(new OAuthApiMetadata()) + .credentials("foo", toStringAndClose(OAuthTestUtils.class.getResourceAsStream("/testpk.pem"))) + .endpoint(url.toString()) + .overrides(overrides) + .modules(ImmutableSet.of(new ExecutorServiceModule(sameThreadExecutor()))) + .buildApi(OAuthApi.class); + } +} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiExpectTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiExpectTest.java deleted file mode 100644 index a44bad175d..0000000000 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiExpectTest.java +++ /dev/null @@ -1,23 +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 org.jclouds.oauth.v2.OAuthApi; - -public class BaseOAuthApiExpectTest extends BaseOAuthExpectTest { - -} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java index aefdcdd934..4652c0c9c2 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java @@ -37,6 +37,7 @@ import org.jclouds.oauth.v2.domain.TokenRequest; import org.testng.annotations.Test; import com.google.common.base.Function; +import com.google.common.collect.ImmutableMap; import com.google.common.reflect.TypeToken; import com.google.inject.Injector; import com.google.inject.Key; @@ -75,18 +76,14 @@ public abstract class BaseOAuthAuthenticatedApiLiveTest ext // obtain the scopes from the subclass String scopes = getScopes(); - Header header = Header.builder().signerAlgorithm(signatureAlgorithm).type("JWT").build(); + Header header = Header.create(signatureAlgorithm, "JWT"); long now = SECONDS.convert(System.currentTimeMillis(), MILLISECONDS); - ClaimSet claimSet = ClaimSet.builder() - .addClaim("aud", audience) - .addClaim("scope", scopes) - .addClaim("iss", identity) - .emissionTime(now) - .expirationTime(now + 3600).build(); + ClaimSet claimSet = ClaimSet.create(now, now + 3600, + ImmutableMap.of("aud", audience, "scope", scopes, "iss", identity)); - TokenRequest tokenRequest = TokenRequest.builder().header(header).claimSet(claimSet).build(); + TokenRequest tokenRequest = TokenRequest.create(header, claimSet); Token token = oauthApi.authenticate(tokenRequest); diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthExpectTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthParseTest.java similarity index 67% rename from apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthExpectTest.java rename to apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthParseTest.java index 18fe151ea5..ae47cfdc7e 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthExpectTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthParseTest.java @@ -16,11 +16,15 @@ */ package org.jclouds.oauth.v2.internal; -import org.jclouds.rest.internal.BaseRestApiExpectTest; +import org.jclouds.json.BaseItemParserTest; +import org.jclouds.json.config.GsonModule; +import org.jclouds.oauth.v2.config.OAuthParserModule; -public class BaseOAuthExpectTest extends BaseRestApiExpectTest { +import com.google.inject.Guice; +import com.google.inject.Injector; - public BaseOAuthExpectTest() { - provider = "oauth"; +public abstract class BaseOAuthParseTest extends BaseItemParserTest { + @Override protected Injector injector() { + return Guice.createInjector(new GsonModule(), new OAuthParserModule()); } } 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/json/JWTTokenRequestFormatTest.java index fa3307fd7e..bc82809cd3 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormatTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormatTest.java @@ -34,6 +34,7 @@ import org.jclouds.util.Strings2; import org.testng.annotations.Test; import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; @Test(groups = "unit") @@ -47,10 +48,10 @@ public class JWTTokenRequestFormatTest { TokenRequestFormat tokenRequestFormat = ContextBuilder.newBuilder(new OAuthApiMetadata()).overrides (OAuthTestUtils.defaultProperties(null)).build().utils() .injector().getInstance(TokenRequestFormat.class); - Header header = new Header.Builder().signerAlgorithm("a").type("b").build(); - ClaimSet claimSet = new ClaimSet.Builder().addClaim("ist", STRING_THAT_GENERATES_URL_UNSAFE_BASE64_ENCODING) - .build(); - TokenRequest tokenRequest = new TokenRequest.Builder().claimSet(claimSet).header(header).build(); + 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); diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java index bcaa9e4a48..d5643591b4 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java @@ -16,15 +16,16 @@ */ package org.jclouds.oauth.v2.parse; -import org.jclouds.json.BaseItemParserTest; -import org.jclouds.oauth.v2.domain.Token; -import org.testng.annotations.Test; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import javax.ws.rs.Consumes; -import javax.ws.rs.core.MediaType; -@Test(groups = "unit") -public class ParseTokenTest extends BaseItemParserTest { +import org.jclouds.oauth.v2.domain.Token; +import org.jclouds.oauth.v2.internal.BaseOAuthParseTest; +import org.testng.annotations.Test; + +@Test(groups = "unit", testName = "ParseTokenTest") +public class ParseTokenTest extends BaseOAuthParseTest { @Override public String resource() { @@ -32,9 +33,8 @@ public class ParseTokenTest extends BaseItemParserTest { } @Override - @Consumes(MediaType.APPLICATION_JSON) + @Consumes(APPLICATION_JSON) public Token expected() { - return Token.builder().expiresIn(3600).tokenType("Bearer").accessToken - ("1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M").build(); + return Token.create("1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M", "Bearer", 3600); } } From cd8aeed16d51ca95a34763c7920a04fefbffac00 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Tue, 28 Oct 2014 22:10:34 -0700 Subject: [PATCH 24/33] Use AutoValue to reduce bulk of Google Storage value types. --- apis/oauth/pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/apis/oauth/pom.xml b/apis/oauth/pom.xml index 7c22dcb366..a13d15b3f0 100644 --- a/apis/oauth/pom.xml +++ b/apis/oauth/pom.xml @@ -51,7 +51,6 @@ com.google.auto.value auto-value - 1.0-rc2 provided From 35156560dc52a975edb20ac2135bf04757823696 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Thu, 30 Oct 2014 21:05:23 -0700 Subject: [PATCH 25/33] Decomplicate OAuth a little. --- .../java/org/jclouds/oauth/v2/OAuthApi.java | 7 +- .../OAuthTokenBinder.java} | 41 ++++------- .../oauth/v2/domain/TokenRequestFormat.java | 45 ------------ .../v2/filters/BearerTokenAuthenticator.java | 20 +++--- .../oauth/v2/filters/OAuthAuthenticator.java | 26 +++---- .../oauth/v2/functions/BuildTokenRequest.java | 34 ++++----- .../oauth/v2/functions/FetchToken.java | 17 ++--- .../functions/OAuthCredentialsSupplier.java | 69 +++++++++---------- .../functions/SignOrProduceMacForToken.java | 51 +++++++------- .../oauth/v2/handlers/OAuthErrorHandler.java | 16 ++--- .../oauth/v2/handlers/OAuthTokenBinder.java | 45 ------------ .../v2/internal/SubtypeAdapterFactory.java | 42 ----------- .../OAuthTokenBinderTest.java} | 15 ++-- 13 files changed, 129 insertions(+), 299 deletions(-) rename apis/oauth/src/main/java/org/jclouds/oauth/v2/{json/JWTTokenRequestFormat.java => binders/OAuthTokenBinder.java} (69%) delete mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequestFormat.java delete mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthTokenBinder.java delete mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/internal/SubtypeAdapterFactory.java rename apis/oauth/src/test/java/org/jclouds/oauth/v2/{json/JWTTokenRequestFormatTest.java => binders/OAuthTokenBinderTest.java} (83%) 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()); From eb8b154869087e79cd1511e3ab5e3aabe0c08941 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sat, 1 Nov 2014 12:31:04 -0700 Subject: [PATCH 26/33] JCLOUDS-750 Remove need for custom json type adapters on OAuth. --- .../jclouds/oauth/v2/OAuthApiMetadata.java | 4 +- .../oauth/v2/config/OAuthParserModule.java | 159 ------------------ .../org/jclouds/oauth/v2/domain/ClaimSet.java | 42 ----- .../org/jclouds/oauth/v2/domain/Claims.java} | 22 ++- .../org/jclouds/oauth/v2/domain/Header.java | 3 + .../org/jclouds/oauth/v2/domain/Token.java | 6 +- .../jclouds/oauth/v2/domain/TokenRequest.java | 8 +- .../oauth/v2/functions/BuildTokenRequest.java | 19 +-- .../v2/binders/OAuthTokenBinderTest.java | 14 +- .../oauth/v2/features/OAuthApiLiveTest.java | 14 +- .../oauth/v2/features/OAuthApiMockTest.java | 15 +- .../BaseOAuthAuthenticatedApiLiveTest.java | 15 +- .../oauth/v2/parse/ParseTokenTest.java | 4 +- 13 files changed, 75 insertions(+), 250 deletions(-) delete mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthParserModule.java delete mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java rename apis/oauth/src/{test/java/org/jclouds/oauth/v2/internal/BaseOAuthParseTest.java => main/java/org/jclouds/oauth/v2/domain/Claims.java} (57%) 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 index d946d702f5..2690c15ff0 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java @@ -25,7 +25,6 @@ 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.oauth.v2.config.OAuthParserModule; import org.jclouds.rest.internal.BaseHttpApiMetadata; import com.google.auto.service.AutoService; @@ -65,8 +64,7 @@ public class OAuthApiMetadata extends BaseHttpApiMetadata { .documentation(URI.create("TODO")) .version("2") .defaultProperties(OAuthApiMetadata.defaultProperties()) - .defaultModules(ImmutableSet - .>of(OAuthModule.class, OAuthParserModule.class, OAuthHttpApiModule.class)); + .defaultModules(ImmutableSet.>of(OAuthModule.class, OAuthHttpApiModule.class)); } @Override diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthParserModule.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthParserModule.java deleted file mode 100644 index 4768e6b644..0000000000 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthParserModule.java +++ /dev/null @@ -1,159 +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.io.IOException; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; - -import javax.inject.Singleton; - -import org.jclouds.oauth.v2.domain.ClaimSet; -import org.jclouds.oauth.v2.domain.Header; -import org.jclouds.oauth.v2.domain.Token; - -import com.google.common.collect.ImmutableSet; -import com.google.gson.Gson; -import com.google.gson.TypeAdapter; -import com.google.gson.TypeAdapterFactory; -import com.google.gson.reflect.TypeToken; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import com.google.inject.AbstractModule; -import com.google.inject.Provides; - -/** Configures type adapter factories for {@link Header}, {@link ClaimSet}, and {@link Token}. */ -public final class OAuthParserModule extends AbstractModule { - @Override protected void configure() { - } - - // TODO: change jclouds core to use collaborative set bindings - @Provides @Singleton public Set typeAdapterFactories() { - return ImmutableSet - .of(new HeaderTypeAdapter(), new ClaimSetTypeAdapter(), new TokenAdapter()); - } - - private static final class HeaderTypeAdapter extends SubtypeAdapterFactory

{ - HeaderTypeAdapter() { - super(Header.class); - } - - @Override public void write(JsonWriter out, Header value) throws IOException { - out.beginObject(); - out.name("alg"); - out.value(value.signerAlgorithm()); - out.name("typ"); - out.value(value.type()); - out.endObject(); - } - - @Override public Header read(JsonReader in) throws IOException { - in.beginObject(); - in.nextName(); - String signerAlgorithm = in.nextString(); - in.nextName(); - String type = in.nextString(); - in.endObject(); - return Header.create(signerAlgorithm, type); - } - } - - private static final class ClaimSetTypeAdapter extends SubtypeAdapterFactory { - ClaimSetTypeAdapter() { - super(ClaimSet.class); - } - - @Override public void write(JsonWriter out, ClaimSet value) throws IOException { - out.beginObject(); - for (Map.Entry entry : value.claims().entrySet()) { - out.name(entry.getKey()); - out.value(entry.getValue()); - } - out.name("exp"); - out.value(value.expirationTime()); - out.name("iat"); - out.value(value.emissionTime()); - out.endObject(); - } - - @Override public ClaimSet read(JsonReader in) throws IOException { - Map claims = new LinkedHashMap(); - in.beginObject(); - while (in.hasNext()) { - claims.put(in.nextName(), in.nextString()); - } - in.endObject(); - return ClaimSet.create(0, 0, Collections.unmodifiableMap(claims)); - } - } - - /** OAuth is used in apis that may not default to snake case. Explicity control case format. */ - private static final class TokenAdapter extends SubtypeAdapterFactory { - TokenAdapter() { - super(Token.class); - } - - @Override public void write(JsonWriter out, Token value) throws IOException { - out.beginObject(); - out.name("access_token"); - out.value(value.accessToken()); - out.name("token_type"); - out.value(value.tokenType()); - out.name("expires_in"); - out.value(value.expiresIn()); - out.endObject(); - } - - @Override public Token read(JsonReader in) throws IOException { - String accessToken = null; - String tokenType = null; - int expiresIn = 0; - in.beginObject(); - while (in.hasNext()) { - String name = in.nextName(); - if (name.equals("access_token")) { - accessToken = in.nextString(); - } else if (name.equals("token_type")) { - tokenType = in.nextString(); - } else if (name.equals("expires_in")) { - expiresIn = in.nextInt(); - } else { - in.skipValue(); - } - } - in.endObject(); - return Token.create(accessToken, tokenType, expiresIn); - } - } - - private abstract static class SubtypeAdapterFactory extends TypeAdapter implements TypeAdapterFactory { - private final Class baseClass; - - private SubtypeAdapterFactory(Class baseClass) { - this.baseClass = baseClass; - } - - @Override public TypeAdapter create(Gson gson, TypeToken typeToken) { - if (!(baseClass.isAssignableFrom(typeToken.getRawType()))) { - return null; - } - return (TypeAdapter) this; - } - } -} diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java deleted file mode 100644 index e265e905db..0000000000 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.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.domain; - -import java.util.Map; - -import com.google.auto.value.AutoValue; - -/** - * The claimset for the {@linkplain Token}. - * - * @see doc - */ -@AutoValue -public abstract class ClaimSet { - - /** The emission time, in seconds since the epoch. */ - public abstract long emissionTime(); - - /** The expiration time, in seconds since the emission time. */ - public abstract long expirationTime(); - - public abstract Map claims(); - - public static ClaimSet create(long emissionTime, long expirationTime, Map claims) { - return new AutoValue_ClaimSet(emissionTime, expirationTime, claims); - } -} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthParseTest.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Claims.java similarity index 57% rename from apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthParseTest.java rename to apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Claims.java index ae47cfdc7e..07b03f646e 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthParseTest.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Claims.java @@ -14,17 +14,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jclouds.oauth.v2.internal; +package org.jclouds.oauth.v2.domain; -import org.jclouds.json.BaseItemParserTest; -import org.jclouds.json.config.GsonModule; -import org.jclouds.oauth.v2.config.OAuthParserModule; +/** + * Description of Claims corresponding to a {@linkplain Token JWT Token}. + * + * @see registered list + */ +public final class Claims { + /** The time at which the JWT was issued, in seconds since the epoch. */ + public static final String ISSUED_AT = "iat"; -import com.google.inject.Guice; -import com.google.inject.Injector; + /** The expiration time, in seconds since {@link #ISSUED_AT}. */ + public static final String EXPIRATION_TIME = "exp"; -public abstract class BaseOAuthParseTest extends BaseItemParserTest { - @Override protected Injector injector() { - return Guice.createInjector(new GsonModule(), new OAuthParserModule()); + private Claims(){ + throw new AssertionError("intentionally unimplemented"); } } 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 index 9146824654..ea83a91697 100644 --- 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 @@ -16,6 +16,8 @@ */ package org.jclouds.oauth.v2.domain; +import org.jclouds.json.SerializedNames; + import com.google.auto.value.AutoValue; /** @@ -32,6 +34,7 @@ public abstract class Header { /** 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); } diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java index cf7ce577f1..548a83f23b 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Token.java @@ -16,6 +16,8 @@ */ package org.jclouds.oauth.v2.domain; +import org.jclouds.json.SerializedNames; + import com.google.auto.value.AutoValue; /** @@ -32,8 +34,8 @@ public abstract class Token { /** In how many seconds this token expires. */ public abstract long expiresIn(); - public static Token - create(String accessToken, String tokenType, long expiresIn) { + @SerializedNames({"access_token", "token_type", "expires_in"}) + public static Token create(String accessToken, String tokenType, long expiresIn) { return new AutoValue_Token(accessToken, tokenType, expiresIn); } } 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 index a0154bf4b1..b08a20ba90 100644 --- 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 @@ -16,14 +16,16 @@ */ 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 ClaimSet claimSet(); + public abstract Map claimSet(); - public static TokenRequest create(Header header, ClaimSet claimSet) { - return new AutoValue_TokenRequest(header, claimSet); + public static TokenRequest create(Header header, Map claims) { + return new AutoValue_TokenRequest(header, claims); } } 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 bcce0047ad..7d94349b51 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 @@ -21,15 +21,15 @@ import static org.jclouds.oauth.v2.OAuthConstants.ADDITIONAL_CLAIMS; import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; import static org.jclouds.oauth.v2.config.OAuthProperties.SCOPES; import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; +import static org.jclouds.oauth.v2.domain.Claims.EXPIRATION_TIME; +import static org.jclouds.oauth.v2.domain.Claims.ISSUED_AT; import java.util.Collections; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; 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; @@ -38,7 +38,6 @@ 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,9 +50,6 @@ import com.google.inject.name.Named; * TODO scopes etc should come from the REST method and not from a global property */ 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 Supplier credentialsSupplier; @@ -92,18 +88,15 @@ public final class BuildTokenRequest implements Function claims = new LinkedHashMap(); + Map claims = new LinkedHashMap(); claims.put("iss", credentialsSupplier.get().identity); claims.put("scope", getOAuthScopes(request)); claims.put("aud", assertionTargetDescription); + claims.put(EXPIRATION_TIME, now + tokenDuration); + claims.put(ISSUED_AT, now); claims.putAll(additionalClaims); - checkState(claims.keySet().containsAll(REQUIRED_CLAIMS), - "not all required claims were present"); - - ClaimSet claimSet = ClaimSet.create(now, now + tokenDuration, Collections.unmodifiableMap(claims)); - - return TokenRequest.create(header, claimSet); + return TokenRequest.create(header, claims); } private String getOAuthScopes(GeneratedHttpRequest request) { diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/binders/OAuthTokenBinderTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/binders/OAuthTokenBinderTest.java index b73d49bb05..fedb691999 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/binders/OAuthTokenBinderTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/binders/OAuthTokenBinderTest.java @@ -16,17 +16,19 @@ */ package org.jclouds.oauth.v2.binders; +import static org.jclouds.oauth.v2.domain.Claims.EXPIRATION_TIME; +import static org.jclouds.oauth.v2.domain.Claims.ISSUED_AT; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertSame; import static org.testng.Assert.assertTrue; import java.io.IOException; +import java.util.Map; import org.jclouds.ContextBuilder; import org.jclouds.http.HttpRequest; import org.jclouds.oauth.v2.OAuthApiMetadata; import org.jclouds.oauth.v2.OAuthTestUtils; -import org.jclouds.oauth.v2.domain.ClaimSet; import org.jclouds.oauth.v2.domain.Header; import org.jclouds.oauth.v2.domain.TokenRequest; import org.jclouds.util.Strings2; @@ -48,9 +50,13 @@ public class OAuthTokenBinderTest { (OAuthTestUtils.defaultProperties(null)).build().utils() .injector().getInstance(OAuthTokenBinder.class); Header header = Header.create("a", "b"); - ClaimSet claimSet = ClaimSet.create(0, 0, - ImmutableMap.of("ist", STRING_THAT_GENERATES_URL_UNSAFE_BASE64_ENCODING)); - TokenRequest tokenRequest = TokenRequest.create(header, claimSet); + + Map claims = ImmutableMap.builder() + .put(ISSUED_AT, 0) + .put(EXPIRATION_TIME, 0) + .put("ist", STRING_THAT_GENERATES_URL_UNSAFE_BASE64_ENCODING).build(); + + TokenRequest tokenRequest = TokenRequest.create(header, claims); HttpRequest request = tokenRequestFormat.bindToRequest( HttpRequest.builder().method("GET").endpoint("http://localhost").build(), tokenRequest); diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java index 5b1e0e6215..fa4bed5646 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java @@ -21,13 +21,15 @@ import static org.jclouds.oauth.v2.OAuthTestUtils.getMandatoryProperty; import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; import static org.jclouds.oauth.v2.config.OAuthProperties.SCOPES; import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; +import static org.jclouds.oauth.v2.domain.Claims.EXPIRATION_TIME; +import static org.jclouds.oauth.v2.domain.Claims.ISSUED_AT; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; +import java.util.Map; import java.util.Properties; import org.jclouds.oauth.v2.OAuthConstants; -import org.jclouds.oauth.v2.domain.ClaimSet; import org.jclouds.oauth.v2.domain.Header; import org.jclouds.oauth.v2.domain.Token; import org.jclouds.oauth.v2.domain.TokenRequest; @@ -71,10 +73,14 @@ public class OAuthApiLiveTest extends BaseOAuthApiLiveTest { long now = nowInSeconds(); - ClaimSet claimSet = ClaimSet.create(now, now + 3600, - ImmutableMap.of("aud", audience, "scope", scopes, "iss", identity)); + Map claims = ImmutableMap.builder() + .put("iss", identity) + .put("scope", scopes) + .put("aud", audience) + .put(EXPIRATION_TIME, now + 3600) + .put(ISSUED_AT, now).build(); - TokenRequest tokenRequest = TokenRequest.create(header, claimSet); + TokenRequest tokenRequest = TokenRequest.create(header, claims); Token token = api.authenticate(tokenRequest); assertNotNull(token, "no token when authenticating " + tokenRequest); diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiMockTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiMockTest.java index 95cc5375be..f76a360946 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiMockTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiMockTest.java @@ -22,11 +22,14 @@ import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static org.jclouds.Constants.PROPERTY_MAX_RETRIES; import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; +import static org.jclouds.oauth.v2.domain.Claims.EXPIRATION_TIME; +import static org.jclouds.oauth.v2.domain.Claims.ISSUED_AT; import static org.jclouds.util.Strings2.toStringAndClose; import static org.testng.Assert.assertEquals; import java.io.IOException; import java.net.URL; +import java.util.Map; import java.util.Properties; import org.jclouds.ContextBuilder; @@ -34,7 +37,6 @@ import org.jclouds.concurrent.config.ExecutorServiceModule; import org.jclouds.oauth.v2.OAuthApi; import org.jclouds.oauth.v2.OAuthApiMetadata; import org.jclouds.oauth.v2.OAuthTestUtils; -import org.jclouds.oauth.v2.domain.ClaimSet; import org.jclouds.oauth.v2.domain.Header; import org.jclouds.oauth.v2.domain.Token; import org.jclouds.oauth.v2.domain.TokenRequest; @@ -61,9 +63,12 @@ public class OAuthApiMockTest { private static final Token TOKEN = Token.create("1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M", "Bearer", 3600); - private static final ClaimSet CLAIM_SET = ClaimSet.create(1328569781, 1328573381, ImmutableMap - .of("iss", "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com", "scope", - "https://www.googleapis.com/auth/prediction", "aud", "https://accounts.google.com/o/oauth2/token")); + private static final Map CLAIMS = ImmutableMap.builder() + .put("iss", "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com") + .put("scope", "https://www.googleapis.com/auth/prediction") + .put("aud", "https://accounts.google.com/o/oauth2/token") + .put(EXPIRATION_TIME, 1328573381) + .put(ISSUED_AT, 1328569781).build(); private static final Header HEADER = Header.create("RS256", "JWT"); @@ -78,7 +83,7 @@ public class OAuthApiMockTest { OAuthApi api = api(server.getUrl("/")); - assertEquals(api.authenticate(TokenRequest.create(HEADER, CLAIM_SET)), TOKEN); + assertEquals(api.authenticate(TokenRequest.create(HEADER, CLAIMS)), TOKEN); RecordedRequest request = server.takeRequest(); assertEquals(request.getMethod(), "POST"); diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java index 4652c0c9c2..c88f65f8ee 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java @@ -15,22 +15,25 @@ * limitations under the License. */ package org.jclouds.oauth.v2.internal; + import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.SECONDS; import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; +import static org.jclouds.oauth.v2.domain.Claims.EXPIRATION_TIME; +import static org.jclouds.oauth.v2.domain.Claims.ISSUED_AT; import static org.testng.Assert.assertNotNull; import java.io.Closeable; +import java.util.Map; import java.util.Properties; import org.jclouds.apis.BaseApiLiveTest; import org.jclouds.config.ValueOfConfigurationKeyOrNull; import org.jclouds.oauth.v2.OAuthApi; import org.jclouds.oauth.v2.OAuthConstants; -import org.jclouds.oauth.v2.domain.ClaimSet; import org.jclouds.oauth.v2.domain.Header; import org.jclouds.oauth.v2.domain.Token; import org.jclouds.oauth.v2.domain.TokenRequest; @@ -80,10 +83,14 @@ public abstract class BaseOAuthAuthenticatedApiLiveTest ext long now = SECONDS.convert(System.currentTimeMillis(), MILLISECONDS); - ClaimSet claimSet = ClaimSet.create(now, now + 3600, - ImmutableMap.of("aud", audience, "scope", scopes, "iss", identity)); + Map claims = ImmutableMap.builder() + .put("iss", identity) + .put("scope", scopes) + .put("aud", audience) + .put(EXPIRATION_TIME, now + 3600) + .put(ISSUED_AT, now).build(); - TokenRequest tokenRequest = TokenRequest.create(header, claimSet); + TokenRequest tokenRequest = TokenRequest.create(header, claims); Token token = oauthApi.authenticate(tokenRequest); diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java index d5643591b4..416ec5ef18 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java @@ -20,12 +20,12 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import javax.ws.rs.Consumes; +import org.jclouds.json.BaseItemParserTest; import org.jclouds.oauth.v2.domain.Token; -import org.jclouds.oauth.v2.internal.BaseOAuthParseTest; import org.testng.annotations.Test; @Test(groups = "unit", testName = "ParseTokenTest") -public class ParseTokenTest extends BaseOAuthParseTest { +public class ParseTokenTest extends BaseItemParserTest { @Override public String resource() { From 639b4806502032c64976c02c5494b78a68985d14 Mon Sep 17 00:00:00 2001 From: Chris Custine Date: Fri, 24 Oct 2014 09:13:05 -0600 Subject: [PATCH 27/33] Fix support for bearer tokens --- .../org/jclouds/oauth/v2/OAuthApiMetadata.java | 3 +++ .../oauth/v2/filters/BearerTokenAuthenticator.java | 2 +- .../v2/functions/OAuthCredentialsSupplier.java | 14 +++++++++++--- .../java/org/jclouds/oauth/v2/OAuthTestUtils.java | 6 ++++-- .../v2/functions/OAuthCredentialsFromPKTest.java | 3 ++- .../v2/functions/OAuthCredentialsSupplierTest.java | 7 ++++--- 6 files changed, 25 insertions(+), 10 deletions(-) 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 index 2690c15ff0..58714e04ef 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java @@ -17,6 +17,8 @@ package org.jclouds.oauth.v2; import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; +import static org.jclouds.oauth.v2.config.CredentialType.SERVICE_ACCOUNT_CREDENTIALS; +import static org.jclouds.oauth.v2.config.OAuthProperties.CREDENTIAL_TYPE; import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; import java.net.URI; @@ -50,6 +52,7 @@ public class OAuthApiMetadata extends BaseHttpApiMetadata { public static Properties defaultProperties() { Properties properties = BaseHttpApiMetadata.defaultProperties(); properties.put(SIGNATURE_OR_MAC_ALGORITHM, "RS256"); + properties.put(CREDENTIAL_TYPE, SERVICE_ACCOUNT_CREDENTIALS); properties.put(PROPERTY_SESSION_INTERVAL, 3600); return properties; } 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 5ff8c5091c..c5d944c61c 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 @@ -34,6 +34,6 @@ public final class BearerTokenAuthenticator implements OAuthAuthenticationFilter } @Override public HttpRequest filter(HttpRequest request) throws HttpException { - return request.toBuilder().addHeader("Authorization", format("%s %s", "Bearer ", creds.get().credential)).build(); + 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/functions/OAuthCredentialsSupplier.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java index cd7e3d6c66..3ec907e2f1 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 @@ -30,16 +30,15 @@ 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.config.CredentialType; 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; @@ -77,16 +76,25 @@ public final class OAuthCredentialsSupplier implements Supplier { private final String keyFactoryAlgorithm; + private final CredentialType credentialType; - @Inject OAuthCredentialsForCredentials(@Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureOrMacAlgorithm) { + @Inject OAuthCredentialsForCredentials(@Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureOrMacAlgorithm, + CredentialType credentialType) { this.keyFactoryAlgorithm = OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES.get(checkNotNull( signatureOrMacAlgorithm, "signatureOrMacAlgorithm")); + this.credentialType = credentialType; } @Override public OAuthCredentials load(Credentials in) { try { String identity = in.identity; String privateKeyInPemFormat = in.credential; + + // If passing Bearer tokens, simply create and pass it along + if (credentialType == CredentialType.BEARER_TOKEN_CREDENTIALS) { + return new OAuthCredentials.Builder().identity(identity).credential(in.credential).build(); + } + if (keyFactoryAlgorithm.equals(NO_ALGORITHM)) { return new OAuthCredentials.Builder().identity(identity).credential(privateKeyInPemFormat).build(); } diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java index 438d6244c8..08d98c1849 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java @@ -18,6 +18,8 @@ package org.jclouds.oauth.v2; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Throwables.propagate; +import static org.jclouds.oauth.v2.OAuthConstants.NO_ALGORITHM; +import static org.jclouds.oauth.v2.config.CredentialType.BEARER_TOKEN_CREDENTIALS; import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; import static org.jclouds.util.Strings2.toStringAndClose; @@ -25,7 +27,6 @@ import java.io.File; import java.io.IOException; import java.util.Properties; -import org.jclouds.oauth.v2.config.CredentialType; import org.jclouds.oauth.v2.config.OAuthProperties; import com.google.common.base.Charsets; @@ -52,7 +53,8 @@ public class OAuthTestUtils { properties.put("oauth.credential", "1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M"); properties.put("oauth.endpoint", "http://localhost:5000/o/oauth2/token"); properties.put(AUDIENCE, "https://accounts.google.com/o/oauth2/token"); - properties.put(OAuthProperties.CREDENTIAL_TYPE, CredentialType.BEARER_TOKEN_CREDENTIALS.toString()); + properties.put(OAuthProperties.CREDENTIAL_TYPE, BEARER_TOKEN_CREDENTIALS.toString()); + properties.put(OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM, NO_ALGORITHM.toString()); return properties; } diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java index e3794d6943..6355a40600 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java @@ -17,6 +17,7 @@ package org.jclouds.oauth.v2.functions; import static com.google.common.base.Suppliers.ofInstance; +import static org.jclouds.oauth.v2.config.CredentialType.SERVICE_ACCOUNT_CREDENTIALS; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; @@ -46,7 +47,7 @@ public class OAuthCredentialsFromPKTest { CertificateException, InvalidKeySpecException { OAuthCredentialsSupplier loader = new OAuthCredentialsSupplier(ofInstance(new Credentials("foo", Files.asCharSource(new File("src/test/resources/testpk.pem"), Charsets.UTF_8).read())), - new OAuthCredentialsForCredentials("RS256"), "RS256"); + new OAuthCredentialsForCredentials("RS256", SERVICE_ACCOUNT_CREDENTIALS), "RS256"); return loader.get(); } diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java index 2b3d094f40..cadb85e6d6 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java @@ -24,6 +24,7 @@ import org.testng.annotations.Test; import java.util.Properties; +import static org.jclouds.oauth.v2.config.CredentialType.SERVICE_ACCOUNT_CREDENTIALS; import static org.jclouds.oauth.v2.functions.OAuthCredentialsSupplier.OAuthCredentialsForCredentials; import static org.testng.Assert.assertNotNull; @@ -33,14 +34,14 @@ public class OAuthCredentialsSupplierTest { @Test(expectedExceptions = AuthorizationException.class) public void testAuthorizationExceptionIsThrownOnBadKeys() { OAuthCredentialsSupplier supplier = new OAuthCredentialsSupplier(Suppliers.ofInstance(new Credentials("MOMMA", - "MIA")), new OAuthCredentialsForCredentials("RS256"), "RS256"); + "FileNotFoundCredential")), new OAuthCredentialsForCredentials("RS256", SERVICE_ACCOUNT_CREDENTIALS), "RS256"); supplier.get(); } @Test(expectedExceptions = IllegalArgumentException.class) public void testGSEChildExceptionsPropagateAsAuthorizationException() { OAuthCredentialsSupplier supplier = new OAuthCredentialsSupplier(Suppliers.ofInstance(new Credentials("MOMMA", - "MIA")), new OAuthCredentialsForCredentials("MOMMA"), "MOMMA"); + "MIA")), new OAuthCredentialsForCredentials("MOMMA", SERVICE_ACCOUNT_CREDENTIALS), "MOMMA"); supplier.get(); } @@ -49,7 +50,7 @@ public class OAuthCredentialsSupplierTest { Credentials validCredentials = new Credentials(propertied.getProperty("oauth.identity"), propertied.getProperty("oauth.credential")); OAuthCredentialsSupplier supplier = new OAuthCredentialsSupplier(Suppliers.ofInstance(validCredentials), - new OAuthCredentialsForCredentials("RS256"), "RS256"); + new OAuthCredentialsForCredentials("RS256", SERVICE_ACCOUNT_CREDENTIALS), "RS256"); assertNotNull(supplier.get()); } } From 7a644f8b6e4a8b85593f2f97204557764d143e35 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Tue, 11 Nov 2014 10:40:47 -0800 Subject: [PATCH 28/33] * Refactor OAuth so that it doesn't require private keys when we aren't signing anything. * Rename constant serviceAccountCredentials to p12PrivateKeyCredentials as this better describes the credential value. --- apis/oauth/README | 6 - apis/oauth/pom.xml | 4 +- .../org/jclouds/oauth/v2/JWSAlgorithms.java | 75 ++++++++++ .../java/org/jclouds/oauth/v2/OAuthApi.java | 8 +- .../jclouds/oauth/v2/OAuthApiMetadata.java | 8 +- .../org/jclouds/oauth/v2/OAuthConstants.java | 78 ----------- ...OAuthTokenBinder.java => TokenBinder.java} | 9 +- .../oauth/v2/config/CredentialType.java | 20 ++- .../{Authentication.java => OAuth.java} | 6 +- .../v2/config/OAuthAuthenticationModule.java | 10 +- .../oauth/v2/config/OAuthHttpApiModule.java | 2 +- .../jclouds/oauth/v2/config/OAuthModule.java | 45 ++++-- .../oauth/v2/config/OAuthProperties.java | 18 +-- .../jclouds/oauth/v2/config/OAuthScopes.java | 3 +- .../org/jclouds/oauth/v2/domain/Header.java | 2 +- .../oauth/v2/domain/OAuthCredentials.java | 129 ----------------- .../v2/filters/BearerTokenAuthenticator.java | 7 +- .../oauth/v2/filters/OAuthAuthenticator.java | 15 +- .../oauth/v2/functions/BuildTokenRequest.java | 92 +++++-------- .../functions/OAuthCredentialsSupplier.java | 130 ------------------ .../v2/functions/PrivateKeySupplier.java | 105 ++++++++++++++ .../functions/SignOrProduceMacForToken.java | 55 +++----- .../oauth/v2/OAuthApiMetadataTest.java | 5 +- .../org/jclouds/oauth/v2/OAuthTestUtils.java | 7 +- ...enBinderTest.java => TokenBinderTest.java} | 7 +- .../oauth/v2/features/OAuthApiLiveTest.java | 17 +-- .../functions/OAuthCredentialsFromPKTest.java | 62 --------- .../OAuthCredentialsSupplierTest.java | 56 -------- .../v2/functions/PrivateKeySupplierTest.java | 83 +++++++++++ .../v2/functions/SignerFunctionTest.java | 9 +- .../v2/handlers/OAuthErrorHandlerTest.java | 16 +-- .../v2/internal/BaseOAuthApiLiveTest.java | 7 +- .../BaseOAuthAuthenticatedApiLiveTest.java | 14 +- 33 files changed, 429 insertions(+), 681 deletions(-) create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/JWSAlgorithms.java delete mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java rename apis/oauth/src/main/java/org/jclouds/oauth/v2/binders/{OAuthTokenBinder.java => TokenBinder.java} (90%) rename apis/oauth/src/main/java/org/jclouds/oauth/v2/config/{Authentication.java => OAuth.java} (97%) delete mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java delete mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/PrivateKeySupplier.java rename apis/oauth/src/test/java/org/jclouds/oauth/v2/binders/{OAuthTokenBinderTest.java => TokenBinderTest.java} (93%) delete mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java delete mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java create mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/PrivateKeySupplierTest.java diff --git a/apis/oauth/README b/apis/oauth/README index 32b571a421..1c5f73b455 100644 --- a/apis/oauth/README +++ b/apis/oauth/README @@ -6,11 +6,6 @@ Mandatory: oauth.endpoint - the endpoint to use for authentication (e.g., "http://accounts.google.com/o/oauth2/token" in Google Api's) oauth.audience - the "audience" of the token request (e.g., "http://accounts.google.com/o/oauth2/token" in Google Api's) -Optional: -- each application may expose a Map of additional claims to be added to the token request, -these should be annotated/named with "oauth.additional-claims" -oauth.signature-or-mac-algorithm - the algorithms to use when signing the token request. - Running the live test: mvn clean install -Plive\ @@ -18,5 +13,4 @@ mvn clean install -Plive\ -Dtest.oauth.credential=\ -Dtest.oauth.endpoint=https://accounts.google.com/o/oauth2/token\ -Dtest.jclouds.oauth.audience=https://accounts.google.com/o/oauth2/token\ - -Dtest.jclouds.oauth.signature-or-mac-algorithm=RS256\ -Dtest.jclouds.oauth.scopes=https://www.googleapis.com/auth/prediction \ No newline at end of file diff --git a/apis/oauth/pom.xml b/apis/oauth/pom.xml index a13d15b3f0..275ce4bda2 100644 --- a/apis/oauth/pom.xml +++ b/apis/oauth/pom.xml @@ -35,7 +35,7 @@ FIX_ME FIX_ME FIX_ME - FIX_ME + RS256 FIX_ME FIX_ME 2 @@ -121,7 +121,7 @@ ${test.oauth.endpoint} ${test.oauth.api-version} ${test.oauth.build-version} - ${test.jclouds.oauth.signature-or-mac-algorithm} + ${test.jclouds.oauth.jws-alg} ${test.jclouds.oauth.audience} ${test.jclouds.oauth.scopes} 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 new file mode 100644 index 0000000000..072fc531d8 --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/JWSAlgorithms.java @@ -0,0 +1,75 @@ +/* + * 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 + *

+ * We only support required + * or recommended algorithms, 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 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> ALG_TO_SIGNATURE_ALG_AND_KEY_FACTORY = ImmutableList.>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 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() { + } +} 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 d3082fc3e2..770e5e824c 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 @@ -24,8 +24,8 @@ import javax.inject.Named; import javax.ws.rs.Consumes; import javax.ws.rs.POST; -import org.jclouds.oauth.v2.binders.OAuthTokenBinder; -import org.jclouds.oauth.v2.config.Authentication; +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; @@ -39,7 +39,7 @@ import org.jclouds.rest.annotations.Endpoint; * OAuthAuthenticator as a request filter, which in turn uses this class to * perform token requests. */ -@Endpoint(Authentication.class) +@Endpoint(OAuth.class) public interface OAuthApi extends Closeable { /** @@ -57,5 +57,5 @@ public interface OAuthApi extends Closeable { @Named("authenticate") @POST @Consumes(APPLICATION_JSON) - Token authenticate(@BinderParam(OAuthTokenBinder.class) TokenRequest tokenRequest) throws AuthorizationException; + Token authenticate(@BinderParam(TokenBinder.class) TokenRequest tokenRequest) throws AuthorizationException; } 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 index 58714e04ef..66f61bbf24 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java @@ -17,9 +17,9 @@ package org.jclouds.oauth.v2; import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; -import static org.jclouds.oauth.v2.config.CredentialType.SERVICE_ACCOUNT_CREDENTIALS; +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.SIGNATURE_OR_MAC_ALGORITHM; +import static org.jclouds.oauth.v2.config.OAuthProperties.JWS_ALG; import java.net.URI; import java.util.Properties; @@ -51,8 +51,8 @@ public class OAuthApiMetadata extends BaseHttpApiMetadata { public static Properties defaultProperties() { Properties properties = BaseHttpApiMetadata.defaultProperties(); - properties.put(SIGNATURE_OR_MAC_ALGORITHM, "RS256"); - properties.put(CREDENTIAL_TYPE, SERVICE_ACCOUNT_CREDENTIALS); + properties.put(JWS_ALG, "RS256"); + properties.put(CREDENTIAL_TYPE, P12_PRIVATE_KEY_CREDENTIALS); properties.put(PROPERTY_SESSION_INTERVAL, 3600); return properties; } diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java deleted file mode 100644 index 9b140d46d9..0000000000 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthConstants.java +++ /dev/null @@ -1,78 +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 com.google.common.collect.ImmutableMap; - -import java.util.Map; - -/** - * The constants for OAuth \ - */ -public final class OAuthConstants { - - /** - * Selected algorithm when a signature or mac isn't required. - */ - public static final String NO_ALGORITHM = "none"; - - /** - * Static mapping between the oauth algorithm name and the Crypto provider signature algorithm name. - * - * @see doc - * @see org.jclouds.oauth.v2.json.JWTTokenRequestFormat - */ - public static final Map OAUTH_ALGORITHM_NAMES_TO_SIGNATURE_ALGORITHM_NAMES = ImmutableMap - .builder() - .put("RS256", "SHA256withRSA") - .put("RS384", "SHA384withRSA") - .put("RS512", "SHA512withRSA") - .put("HS256", "HmacSHA256") - .put("HS384", "HmacSHA384") - .put("HS512", "HmacSHA512") - .put("ES256", "SHA256withECDSA") - .put("ES384", "SHA384withECDSA") - .put("ES512", "SHA512withECDSA") - .put(NO_ALGORITHM, NO_ALGORITHM).build(); - - /** - * Static mapping between the oauth algorithm name and the Crypto provider KeyFactory algorithm name. - * - * @see doc - */ - public static final Map OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES = ImmutableMap - .builder() - .put("RS256", "RSA") - .put("RS384", "RSA") - .put("RS512", "RSA") - .put("HS256", "DiffieHellman") - .put("HS384", "DiffieHellman") - .put("HS512", "DiffieHellman") - .put("ES256", "EC") - .put("ES384", "EC") - .put("ES512", "EC") - .put(NO_ALGORITHM, NO_ALGORITHM).build(); - - /** - * The (optional) set of additional claims to use, provided in Map form - */ - public static final String ADDITIONAL_CLAIMS = "jclouds.oauth.additional-claims"; - - private OAuthConstants() { - throw new AssertionError("intentionally unimplemented"); - } -} diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/binders/OAuthTokenBinder.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/binders/TokenBinder.java similarity index 90% rename from apis/oauth/src/main/java/org/jclouds/oauth/v2/binders/OAuthTokenBinder.java rename to apis/oauth/src/main/java/org/jclouds/oauth/v2/binders/TokenBinder.java index e62d9c73f3..078200088a 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/binders/OAuthTokenBinder.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/binders/TokenBinder.java @@ -30,6 +30,7 @@ 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; /** @@ -41,15 +42,15 @@ import com.google.common.collect.ImmutableMultimap; *

  • Creates the full url encoded payload as described in: OAuth2ServiceAccount
  • * */ -public final class OAuthTokenBinder implements Binder { +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 Function signer; + private final Supplier> signer; private final Json json; - @Inject OAuthTokenBinder(Function signer, Json json) { + @Inject TokenBinder(Supplier> signer, Json json) { this.signer = signer; this.json = json; } @@ -62,7 +63,7 @@ public final class OAuthTokenBinder implements Binder { encodedHeader = base64Url().omitPadding().encode(encodedHeader.getBytes(UTF_8)); encodedClaimSet = base64Url().omitPadding().encode(encodedClaimSet.getBytes(UTF_8)); - byte[] signature = signer.apply(on(".").join(encodedHeader, encodedClaimSet).getBytes(UTF_8)); + 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 diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/CredentialType.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/CredentialType.java index 24a658b1fe..141564b57d 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/CredentialType.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/CredentialType.java @@ -16,27 +16,23 @@ */ package org.jclouds.oauth.v2.config; +import static com.google.common.base.CaseFormat.LOWER_CAMEL; +import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE; import static com.google.common.base.Preconditions.checkNotNull; -import com.google.common.base.CaseFormat; - -/** - * Decides what type of credentials createContext is supplied with. - */ +/** Defines the contents of the credential field in {@link org.jclouds.ContextBuilder#credentials(String, String)}. */ public enum CredentialType { BEARER_TOKEN_CREDENTIALS, - SERVICE_ACCOUNT_CREDENTIALS; + /** Contents are a PEM-encoded P12 Private Key. */ + P12_PRIVATE_KEY_CREDENTIALS; - @Override - public String toString() { - return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, name()); + @Override public String toString() { + return UPPER_UNDERSCORE.to(LOWER_CAMEL, name()); } public static CredentialType fromValue(String credentialType) { - return valueOf(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, checkNotNull(credentialType, - "credentialType"))); + return valueOf(LOWER_CAMEL.to(UPPER_UNDERSCORE, checkNotNull(credentialType, "credentialType"))); } - } diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authentication.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuth.java similarity index 97% rename from apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authentication.java rename to apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuth.java index 24f6851467..6255e50442 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authentication.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuth.java @@ -16,13 +16,13 @@ */ package org.jclouds.oauth.v2.config; - -import javax.inject.Qualifier; 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. * @@ -31,5 +31,5 @@ import java.lang.annotation.Target; @Retention(value = RetentionPolicy.RUNTIME) @Target(value = {ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD}) @Qualifier -public @interface Authentication { +public @interface OAuth { } 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 index fb2d4137cc..4d238f123d 100644 --- 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 @@ -30,9 +30,6 @@ import com.google.common.base.Suppliers; import com.google.inject.AbstractModule; import com.google.inject.Provides; -/** - * An OAuth module to be used form other providers. - */ public class OAuthAuthenticationModule extends AbstractModule { @Override @@ -40,13 +37,10 @@ public class OAuthAuthenticationModule extends AbstractModule { bindHttpApi(binder(), OAuthApi.class); } - /** - * When oauth is used as a module the oauth endpoint is a normal property - */ @Provides @Singleton - @Authentication - protected Supplier provideAuthenticationEndpoint(@Named("oauth.endpoint") String endpoint) { + @OAuth + protected Supplier oauthEndpoint(@Named("oauth.endpoint") String endpoint) { return Suppliers.ofInstance(URI.create(endpoint)); } } 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 index 6b4fdf959e..3bb7c1aaa3 100644 --- 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 @@ -37,7 +37,7 @@ public class OAuthHttpApiModule extends HttpApiModule { @Provides @Singleton - @Authentication + @OAuth protected Supplier provideAuthenticationEndpoint(ProviderMetadata providerMetadata) { return Suppliers.ofInstance(URI.create(providerMetadata.getEndpoint())); } 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 788dac47cc..e831c0f8f9 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,11 +16,14 @@ */ 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 java.util.concurrent.TimeUnit; +import java.security.PrivateKey; -import org.jclouds.oauth.v2.domain.OAuthCredentials; +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; @@ -28,12 +31,12 @@ 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.OAuthCredentialsSupplier; +import org.jclouds.oauth.v2.functions.PrivateKeySupplier; import org.jclouds.oauth.v2.functions.SignOrProduceMacForToken; -import org.jclouds.rest.internal.GeneratedHttpRequest; import com.google.common.base.Function; 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; @@ -48,11 +51,10 @@ import com.google.inject.name.Named; public class OAuthModule extends AbstractModule { @Override protected void configure() { - bind(new TypeLiteral>() {}).to(SignOrProduceMacForToken.class); bind(CredentialType.class).toProvider(CredentialTypeFromPropertyOrDefault.class); - bind(new TypeLiteral>() {}).to(OAuthCredentialsSupplier.class); - bind(new TypeLiteral>() {}).to(BuildTokenRequest.class); + bind(new TypeLiteral>() {}).to(BuildTokenRequest.class); bind(new TypeLiteral>() {}).to(FetchToken.class); + bind(new TypeLiteral>() {}).annotatedWith(OAuth.class).to(PrivateKeySupplier.class); } /** @@ -65,21 +67,34 @@ public class OAuthModule extends AbstractModule { @Provides @Singleton public LoadingCache provideAccessCache(Function getAccess, - @Named(PROPERTY_SESSION_INTERVAL) long - sessionIntervalInSeconds) { + @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 - sessionIntervalInSeconds = sessionIntervalInSeconds > 30 ? sessionIntervalInSeconds - 30 : - sessionIntervalInSeconds; - return CacheBuilder.newBuilder().expireAfterWrite(sessionIntervalInSeconds, TimeUnit.SECONDS).build(CacheLoader - .from(getAccess)); + 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> signOrProduceMacForToken(@Named(JWS_ALG) String jwsAlg, + Provider in) { + if (jwsAlg.equals(NONE)) { // Current implementation requires we return null on none. + return Suppliers.>ofInstance(new Function() { + @Override public byte[] apply(byte[] input) { + return null; + } + }); + } + return Suppliers.memoize(in.get()); } @Singleton public static class CredentialTypeFromPropertyOrDefault implements Provider { @Inject(optional = true) @Named(OAuthProperties.CREDENTIAL_TYPE) - String credentialType = CredentialType.SERVICE_ACCOUNT_CREDENTIALS.toString(); + String credentialType = CredentialType.P12_PRIVATE_KEY_CREDENTIALS.toString(); @Override public CredentialType get() { @@ -93,7 +108,7 @@ public class OAuthModule extends AbstractModule { OAuthAuthenticator serviceAccountAuth, BearerTokenAuthenticator bearerTokenAuth) { switch (credentialType) { - case SERVICE_ACCOUNT_CREDENTIALS: + case P12_PRIVATE_KEY_CREDENTIALS: return serviceAccountAuth; case BEARER_TOKEN_CREDENTIALS: return bearerTokenAuth; 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 9394cad09c..197bc310c3 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,17 +16,12 @@ */ package org.jclouds.oauth.v2.config; -/** - * Configurable properties for jclouds OAuth - */ +import org.jclouds.oauth.v2.JWSAlgorithms; + public class OAuthProperties { - /** - * The selected signature algorithm to use to sign the requests. - *

    - * This refers to the name the oauth provider expects, i.e., "RSA - */ - public static final String SIGNATURE_OR_MAC_ALGORITHM = "jclouds.oauth.signature-or-mac-algorithm"; + /** The JSON Web Signature alg, from the {@link JWSAlgorithms#supportedAlgs() supported list}. */ + 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 @@ -36,11 +31,6 @@ public class OAuthProperties { */ public static final String AUDIENCE = "jclouds.oauth.audience"; - /** - * Optional list of comma-separated scopes to use when no OAuthScopes annotation is present. - */ - public static final String SCOPES = "jclouds.oauth.scopes"; - /** * Specify if credentials are id + private key or if you are reusing an oauth2 token. * diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java index 57ffd29b4a..d4fe7d4a92 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java @@ -16,12 +16,13 @@ */ package org.jclouds.oauth.v2.config; -import javax.inject.Qualifier; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import javax.inject.Qualifier; + /** * Used to annotate REST methods/ifaces that use OAuthAuthentication. *

    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 index ea83a91697..9cdd924fa8 100644 --- 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 @@ -28,7 +28,7 @@ import com.google.auto.value.AutoValue; @AutoValue public abstract class Header { - /** The name of the algorithm used to compute the signature, e.g., {@code RS256}. */ + /** 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}. */ diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java deleted file mode 100644 index 78cb402d08..0000000000 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java +++ /dev/null @@ -1,129 +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.common.base.Objects; -import org.jclouds.domain.Credentials; - -import java.security.PrivateKey; - -import static com.google.common.base.Objects.equal; -import static com.google.common.base.Objects.toStringHelper; -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Special kind credentials for oauth authentication that includes {@link java.security.PrivateKey} to sign - * requests. - */ -public class OAuthCredentials extends Credentials { - - public static Builder builder() { - return new Builder(); - } - - public Builder toBuilder() { - return builder().fromOauthCredentials(this); - } - - public static class Builder extends Credentials.Builder { - - protected PrivateKey privateKey; - - /** - * @see OAuthCredentials#privateKey - */ - public Builder privateKey(PrivateKey privateKey) { - this.privateKey = checkNotNull(privateKey); - return this; - } - - /** - * @see Credentials#identity - */ - public Builder identity(String identity) { - this.identity = checkNotNull(identity); - return this; - } - - /** - * @see Credentials#credential - */ - public Builder credential(String credential) { - this.credential = credential; - return this; - } - - public OAuthCredentials build() { - return new OAuthCredentials(checkNotNull(identity), credential, privateKey); - } - - public Builder fromOauthCredentials(OAuthCredentials credentials) { - return new Builder().privateKey(credentials.privateKey).identity(credentials.identity) - .credential(credentials.credential); - } - } - - /** - * The private key associated with Credentials#identity. - * Used to sign token requests. - */ - public final PrivateKey privateKey; - - public OAuthCredentials(String identity, String credential, PrivateKey privateKey) { - super(identity, credential); - this.privateKey = privateKey; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - OAuthCredentials other = (OAuthCredentials) obj; - return equal(this.identity, other.identity) && equal(this.credential, - other.credential) && equal(this.privateKey, - other.privateKey); - } - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - return Objects.hashCode(identity, credential, privateKey); - } - - /** - * {@inheritDoc} - */ - @Override - public String toString() { - return string().toString(); - } - - protected Objects.ToStringHelper string() { - return toStringHelper(this).omitNullValues().add("identity", identity) - .add("credential", credential != null ? credential.hashCode() : null).add("privateKey", - privateKey.hashCode()); - } -} 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 c5d944c61c..3d7d92d03b 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 @@ -20,16 +20,17 @@ 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.oauth.v2.domain.OAuthCredentials; +import org.jclouds.location.Provider; import com.google.common.base.Supplier; public final class BearerTokenAuthenticator implements OAuthAuthenticationFilter { - private final Supplier creds; + private final Supplier creds; - @Inject BearerTokenAuthenticator(Supplier creds) { + @Inject BearerTokenAuthenticator(@Provider Supplier creds) { this.creds = creds; } 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 28a2c15a5c..cb858b50f7 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,15 +16,12 @@ */ package org.jclouds.oauth.v2.filters; -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 com.google.common.base.Function; import com.google.common.cache.LoadingCache; @@ -36,21 +33,19 @@ import com.google.common.cache.LoadingCache; */ public final class OAuthAuthenticator implements OAuthAuthenticationFilter { - private Function tokenRequestBuilder; + private Function tokenRequestBuilder; private Function tokenFetcher; - @Inject OAuthAuthenticator(Function tokenRequestBuilder, + @Inject OAuthAuthenticator(Function tokenRequestBuilder, LoadingCache tokenFetcher) { this.tokenRequestBuilder = tokenRequestBuilder; this.tokenFetcher = tokenFetcher; } @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); + TokenRequest tokenRequest = tokenRequestBuilder.apply(request); Token token = tokenFetcher.apply(tokenRequest); - return request.toBuilder().addHeader("Authorization", String.format("%s %s", - token.tokenType(), token.accessToken())).build(); + String authorization = String.format("%s %s", token.tokenType(), token.accessToken()); + return request.toBuilder().addHeader("Authorization", authorization).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 7d94349b51..4a51954758 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 @@ -17,21 +17,23 @@ package org.jclouds.oauth.v2.functions; import static com.google.common.base.Preconditions.checkState; -import static org.jclouds.oauth.v2.OAuthConstants.ADDITIONAL_CLAIMS; +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.SCOPES; -import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; +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.Collections; import java.util.LinkedHashMap; import java.util.Map; -import org.jclouds.Constants; +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.OAuthCredentials; import org.jclouds.oauth.v2.domain.TokenRequest; import org.jclouds.rest.internal.GeneratedHttpRequest; @@ -39,83 +41,65 @@ import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.base.Supplier; import com.google.common.reflect.Invokable; -import com.google.inject.Inject; -import com.google.inject.name.Named; -/** - * The default authenticator. - *

    - * Builds the default token request with the following claims: iss,scope,aud,iat,exp. - *

    - * TODO scopes etc should come from the REST method and not from a global property - */ -public final class BuildTokenRequest implements Function { +/** Builds the default token request with the following claims: {@code iss,scope,aud,iat,exp}. */ +public class BuildTokenRequest implements Function { + private static final Joiner ON_COMMA = Joiner.on(","); + private final String assertionTargetDescription; private final String signatureAlgorithm; - private final Supplier credentialsSupplier; + private final Supplier credentialsSupplier; private final long tokenDuration; - @Inject(optional = true) - @Named(ADDITIONAL_CLAIMS) - private Map additionalClaims = Collections.emptyMap(); - - @Inject(optional = true) - @Named(SCOPES) - private String globalScopes = null; - - // injectable so expect tests can override with a predictable value - @Inject(optional = true) - private Supplier timeSourceMillisSinceEpoch = new Supplier() { - @Override - public Long get() { - return System.currentTimeMillis(); + public static class TestBuildTokenRequest extends BuildTokenRequest { + @Inject TestBuildTokenRequest(@Named(AUDIENCE) String assertionTargetDescription, + @Named(JWS_ALG) String signatureAlgorithm, @Provider Supplier credentialsSupplier, + @Named(PROPERTY_SESSION_INTERVAL) long tokenDuration) { + super(assertionTargetDescription, signatureAlgorithm, credentialsSupplier, tokenDuration); } - }; + + public long currentTimeSeconds() { + return 0; + } + } @Inject BuildTokenRequest(@Named(AUDIENCE) String assertionTargetDescription, - @Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureAlgorithm, - Supplier credentialsSupplier, - @Named(Constants.PROPERTY_SESSION_INTERVAL) long tokenDuration) { + @Named(JWS_ALG) String signatureAlgorithm, @Provider Supplier credentialsSupplier, + @Named(PROPERTY_SESSION_INTERVAL) long tokenDuration) { this.assertionTargetDescription = assertionTargetDescription; this.signatureAlgorithm = signatureAlgorithm; this.credentialsSupplier = credentialsSupplier; this.tokenDuration = tokenDuration; } - @Override public TokenRequest apply(GeneratedHttpRequest request) { - long now = timeSourceMillisSinceEpoch.get() / 1000; - - // fetch the token + @Override public TokenRequest apply(HttpRequest request) { Header header = Header.create(signatureAlgorithm, "JWT"); Map claims = new LinkedHashMap(); claims.put("iss", credentialsSupplier.get().identity); - claims.put("scope", getOAuthScopes(request)); + claims.put("scope", getOAuthScopes((GeneratedHttpRequest) request)); claims.put("aud", assertionTargetDescription); + + long now = currentTimeSeconds(); claims.put(EXPIRATION_TIME, now + tokenDuration); claims.put(ISSUED_AT, now); - claims.putAll(additionalClaims); return TokenRequest.create(header, claims); } + //TODO: Remove and switch to a request function. private String getOAuthScopes(GeneratedHttpRequest request) { Invokable invokable = request.getInvocation().getInvokable(); - OAuthScopes classScopes = invokable.getOwnerType().getRawType().getAnnotation(OAuthScopes.class); OAuthScopes methodScopes = invokable.getAnnotation(OAuthScopes.class); - - // if no annotations are present the rely on globally set scopes - if (classScopes == null && methodScopes == null) { - checkState(globalScopes != null, String.format("REST class or method should be annotated " + - "with OAuthScopes specifying required permissions. Alternatively a global property " + - "\"oauth.scopes\" may be set to define scopes globally. REST Class: %s, Method: %s", - invokable.getOwnerType(), - invokable.getName())); - return globalScopes; - } - + checkState(classScopes != null || methodScopes != null, "Api interface or method should be annotated " // + + "with OAuthScopes specifying required permissions. Api interface: %s, Method: %s", // + invokable.getOwnerType(), invokable.getName()); OAuthScopes scopes = methodScopes != null ? methodScopes : classScopes; - return Joiner.on(",").join(scopes.value()); + return ON_COMMA.join(scopes.value()); + } + + long currentTimeSeconds() { + return System.currentTimeMillis() / 1000; } } 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 deleted file mode 100644 index 3ec907e2f1..0000000000 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java +++ /dev/null @@ -1,130 +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.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Throwables.propagate; -import static java.lang.String.format; -import static org.jclouds.crypto.Pems.privateKeySpec; -import static org.jclouds.oauth.v2.OAuthConstants.NO_ALGORITHM; -import static org.jclouds.oauth.v2.OAuthConstants.OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES; -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.config.CredentialType; -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 // due to cache -public final class OAuthCredentialsSupplier implements Supplier { - - private final Supplier creds; - private final LoadingCache keyCache; - - @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), - format("No mapping for key factory for algorithm: %s", signatureOrMacAlgorithm)); - // 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 OAuthCredentialsForCredentials extends CacheLoader { - private final String keyFactoryAlgorithm; - private final CredentialType credentialType; - - @Inject OAuthCredentialsForCredentials(@Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureOrMacAlgorithm, - CredentialType credentialType) { - this.keyFactoryAlgorithm = OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES.get(checkNotNull( - signatureOrMacAlgorithm, "signatureOrMacAlgorithm")); - this.credentialType = credentialType; - } - - @Override public OAuthCredentials load(Credentials in) { - try { - String identity = in.identity; - String privateKeyInPemFormat = in.credential; - - // If passing Bearer tokens, simply create and pass it along - if (credentialType == CredentialType.BEARER_TOKEN_CREDENTIALS) { - return new OAuthCredentials.Builder().identity(identity).credential(in.credential).build(); - } - - if (keyFactoryAlgorithm.equals(NO_ALGORITHM)) { - return new OAuthCredentials.Builder().identity(identity).credential(privateKeyInPemFormat).build(); - } - KeyFactory keyFactory = KeyFactory.getInstance(keyFactoryAlgorithm); - PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec(ByteSource.wrap( - privateKeyInPemFormat.getBytes(Charsets.UTF_8)))); - return new OAuthCredentials.Builder().identity(identity).credential(privateKeyInPemFormat) - .privateKey(privateKey).build(); - } catch (IOException e) { - throw propagate(e); - // catch security exceptions InvalidKeySpecException and NoSuchAlgorithmException as GSE - } catch (GeneralSecurityException 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 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) { - AuthorizationException authorizationException = getFirstThrowableOfType(e, AuthorizationException.class); - if (authorizationException != null) { - throw authorizationException; - } - throw e; - } - } -} 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 new file mode 100644 index 0000000000..cbdad5ef45 --- /dev/null +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/PrivateKeySupplier.java @@ -0,0 +1,105 @@ +/* + * 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 { + + private final Supplier creds; + private final LoadingCache keyCache; + + @Inject PrivateKeySupplier(@Provider Supplier 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 { + 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; + } + } +} 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 647fcfae26..fd827b1751 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,12 +16,9 @@ */ package org.jclouds.oauth.v2.functions; -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 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; @@ -29,57 +26,43 @@ import java.security.PrivateKey; import java.security.Signature; import java.security.SignatureException; -import javax.annotation.PostConstruct; import javax.crypto.Mac; import javax.inject.Inject; import javax.inject.Named; -import org.jclouds.oauth.v2.domain.OAuthCredentials; +import org.jclouds.oauth.v2.config.OAuth; +import org.jclouds.rest.AuthorizationException; 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} */ -@Singleton // due to signatureOrMacFunction -public final class SignOrProduceMacForToken implements Function { +public final class SignOrProduceMacForToken implements Supplier> { - private final Supplier credentials; - private final String signatureOrMacAlgorithm; - private Function signatureOrMacFunction; + private final String macOrSignature; + private final Supplier credentials; - @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)); - this.signatureOrMacAlgorithm = OAUTH_ALGORITHM_NAMES_TO_SIGNATURE_ALGORITHM_NAMES.get(signatureOrMacAlgorithm); + @Inject SignOrProduceMacForToken(@Named(JWS_ALG) String jwsAlg, @OAuth Supplier credentials) { + this.macOrSignature = macOrSignature(jwsAlg); this.credentials = credentials; } - @PostConstruct - public void loadSignatureOrMacOrNone() throws InvalidKeyException, NoSuchAlgorithmException { - if (signatureOrMacAlgorithm.equals(NO_ALGORITHM)) { - this.signatureOrMacFunction = new Function() { - @Override - public byte[] apply(byte[] input) { - return null; - } - }; - } else if (signatureOrMacAlgorithm.startsWith("SHA")) { - this.signatureOrMacFunction = new SignatureGenerator(signatureOrMacAlgorithm, credentials.get().privateKey); - } else { - this.signatureOrMacFunction = new MessageAuthenticationCodeGenerator(signatureOrMacAlgorithm, - credentials.get().privateKey); + @Override public Function 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); } } - @Override public byte[] apply(byte[] input) { - return signatureOrMacFunction.apply(input); - } - private static class MessageAuthenticationCodeGenerator implements Function { private final Mac mac; diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java index d6ea17f60d..3bd0456732 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java @@ -16,12 +16,13 @@ */ package org.jclouds.oauth.v2; -import com.google.common.collect.ImmutableSet; -import com.google.common.reflect.TypeToken; import org.jclouds.View; import org.jclouds.apis.internal.BaseApiMetadataTest; import org.testng.annotations.Test; +import com.google.common.collect.ImmutableSet; +import com.google.common.reflect.TypeToken; + /** * Tests that OAuthApiMetadata is properly registered in ServiceLoader *

    diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java index 08d98c1849..ed512d360c 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java @@ -18,17 +18,15 @@ package org.jclouds.oauth.v2; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Throwables.propagate; -import static org.jclouds.oauth.v2.OAuthConstants.NO_ALGORITHM; import static org.jclouds.oauth.v2.config.CredentialType.BEARER_TOKEN_CREDENTIALS; import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; +import static org.jclouds.oauth.v2.config.OAuthProperties.CREDENTIAL_TYPE; import static org.jclouds.util.Strings2.toStringAndClose; import java.io.File; import java.io.IOException; import java.util.Properties; -import org.jclouds.oauth.v2.config.OAuthProperties; - import com.google.common.base.Charsets; import com.google.common.io.Files; @@ -53,8 +51,7 @@ public class OAuthTestUtils { properties.put("oauth.credential", "1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M"); properties.put("oauth.endpoint", "http://localhost:5000/o/oauth2/token"); properties.put(AUDIENCE, "https://accounts.google.com/o/oauth2/token"); - properties.put(OAuthProperties.CREDENTIAL_TYPE, BEARER_TOKEN_CREDENTIALS.toString()); - properties.put(OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM, NO_ALGORITHM.toString()); + properties.put(CREDENTIAL_TYPE, BEARER_TOKEN_CREDENTIALS.toString()); return properties; } diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/binders/OAuthTokenBinderTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/binders/TokenBinderTest.java similarity index 93% rename from apis/oauth/src/test/java/org/jclouds/oauth/v2/binders/OAuthTokenBinderTest.java rename to apis/oauth/src/test/java/org/jclouds/oauth/v2/binders/TokenBinderTest.java index fedb691999..2f56aafc00 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/binders/OAuthTokenBinderTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/binders/TokenBinderTest.java @@ -39,16 +39,15 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; @Test(groups = "unit", testName = "OAuthTokenBinderTest") -public class OAuthTokenBinderTest { +public class TokenBinderTest { public static final String STRING_THAT_GENERATES_URL_UNSAFE_BASE64_ENCODING = "§1234567890'+±!\"#$%&/()" + "=?*qwertyuiopº´WERTYUIOPªàsdfghjklç~ASDFGHJKLÇ^ZXCVBNM;:_@€"; public void testPayloadIsUrlSafe() throws IOException { - - OAuthTokenBinder tokenRequestFormat = ContextBuilder.newBuilder(new OAuthApiMetadata()).overrides + TokenBinder tokenRequestFormat = ContextBuilder.newBuilder(new OAuthApiMetadata()).overrides (OAuthTestUtils.defaultProperties(null)).build().utils() - .injector().getInstance(OAuthTokenBinder.class); + .injector().getInstance(TokenBinder.class); Header header = Header.create("a", "b"); Map claims = ImmutableMap.builder() diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java index fa4bed5646..a48b725c7d 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java @@ -19,8 +19,7 @@ package org.jclouds.oauth.v2.features; import static com.google.common.base.Preconditions.checkState; import static org.jclouds.oauth.v2.OAuthTestUtils.getMandatoryProperty; import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; -import static org.jclouds.oauth.v2.config.OAuthProperties.SCOPES; -import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; +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 static org.testng.Assert.assertNotNull; @@ -29,7 +28,7 @@ import static org.testng.Assert.assertTrue; import java.util.Map; import java.util.Properties; -import org.jclouds.oauth.v2.OAuthConstants; +import org.jclouds.oauth.v2.JWSAlgorithms; import org.jclouds.oauth.v2.domain.Header; import org.jclouds.oauth.v2.domain.Token; import org.jclouds.oauth.v2.domain.TokenRequest; @@ -45,7 +44,7 @@ import com.google.common.collect.ImmutableMap; * - test.oauth.credential * - test.jclouds.oauth.audience * - test.jclouds.oauth.scopes - * - test.jclouds.oauth.signature-or-mac-algorithm + * - test.jclouds.oauth.jws-alg */ @Test(groups = "live", singleThreaded = true) public class OAuthApiLiveTest extends BaseOAuthApiLiveTest { @@ -56,19 +55,17 @@ public class OAuthApiLiveTest extends BaseOAuthApiLiveTest { protected Properties setupProperties() { properties = super.setupProperties(); return properties; - } @Test(groups = "live", singleThreaded = true) public void testAuthenticateJWTToken() throws Exception { assertTrue(properties != null, "properties were not set"); - String signatureAlgorithm = getMandatoryProperty(properties, SIGNATURE_OR_MAC_ALGORITHM); - checkState(OAuthConstants.OAUTH_ALGORITHM_NAMES_TO_SIGNATURE_ALGORITHM_NAMES.containsKey(signatureAlgorithm) - , String.format("Algorithm not supported: " + signatureAlgorithm)); + String jwsAlg = getMandatoryProperty(properties, JWS_ALG); + checkState(JWSAlgorithms.supportedAlgs().contains(jwsAlg), "Algorithm not supported: %s", jwsAlg); - Header header = Header.create(signatureAlgorithm, "JWT"); + Header header = Header.create(jwsAlg, "JWT"); - String scopes = getMandatoryProperty(properties, SCOPES); + String scopes = getMandatoryProperty(properties, "jclouds.oauth.scopes"); String audience = getMandatoryProperty(properties, AUDIENCE); long now = nowInSeconds(); diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java deleted file mode 100644 index 6355a40600..0000000000 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsFromPKTest.java +++ /dev/null @@ -1,62 +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.Suppliers.ofInstance; -import static org.jclouds.oauth.v2.config.CredentialType.SERVICE_ACCOUNT_CREDENTIALS; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; - -import java.io.File; -import java.io.IOException; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateException; -import java.security.spec.InvalidKeySpecException; - -import com.google.common.base.Charsets; -import com.google.common.io.Files; - -import org.jclouds.domain.Credentials; -import org.jclouds.oauth.v2.domain.OAuthCredentials; -import org.jclouds.oauth.v2.functions.OAuthCredentialsSupplier.OAuthCredentialsForCredentials; -import org.testng.annotations.Test; - -/** - * Test loading the credentials by extracting a pk from a PKCS12 keystore. - */ -@Test(groups = "unit") -public class OAuthCredentialsFromPKTest { - - public static OAuthCredentials loadOAuthCredentials() throws IOException, NoSuchAlgorithmException, - CertificateException, InvalidKeySpecException { - OAuthCredentialsSupplier loader = new OAuthCredentialsSupplier(ofInstance(new Credentials("foo", - Files.asCharSource(new File("src/test/resources/testpk.pem"), Charsets.UTF_8).read())), - new OAuthCredentialsForCredentials("RS256", SERVICE_ACCOUNT_CREDENTIALS), "RS256"); - return loader.get(); - } - - - public void testLoadPKString() throws IOException, NoSuchAlgorithmException, KeyStoreException, - CertificateException, UnrecoverableKeyException, InvalidKeySpecException { - OAuthCredentials creds = loadOAuthCredentials(); - assertNotNull(creds); - assertEquals(creds.identity, "foo"); - assertNotNull(creds.privateKey); - } -} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java deleted file mode 100644 index cadb85e6d6..0000000000 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplierTest.java +++ /dev/null @@ -1,56 +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 com.google.common.base.Suppliers; -import org.jclouds.domain.Credentials; -import org.jclouds.oauth.v2.OAuthTestUtils; -import org.jclouds.rest.AuthorizationException; -import org.testng.annotations.Test; - -import java.util.Properties; - -import static org.jclouds.oauth.v2.config.CredentialType.SERVICE_ACCOUNT_CREDENTIALS; -import static org.jclouds.oauth.v2.functions.OAuthCredentialsSupplier.OAuthCredentialsForCredentials; -import static org.testng.Assert.assertNotNull; - -@Test(groups = "unit") -public class OAuthCredentialsSupplierTest { - - @Test(expectedExceptions = AuthorizationException.class) - public void testAuthorizationExceptionIsThrownOnBadKeys() { - OAuthCredentialsSupplier supplier = new OAuthCredentialsSupplier(Suppliers.ofInstance(new Credentials("MOMMA", - "FileNotFoundCredential")), new OAuthCredentialsForCredentials("RS256", SERVICE_ACCOUNT_CREDENTIALS), "RS256"); - supplier.get(); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void testGSEChildExceptionsPropagateAsAuthorizationException() { - OAuthCredentialsSupplier supplier = new OAuthCredentialsSupplier(Suppliers.ofInstance(new Credentials("MOMMA", - "MIA")), new OAuthCredentialsForCredentials("MOMMA", SERVICE_ACCOUNT_CREDENTIALS), "MOMMA"); - supplier.get(); - } - - public void testCredentialsAreLoadedOnRightAlgoAndCredentials() { - Properties propertied = OAuthTestUtils.defaultProperties(new Properties()); - Credentials validCredentials = new Credentials(propertied.getProperty("oauth.identity"), - propertied.getProperty("oauth.credential")); - OAuthCredentialsSupplier supplier = new OAuthCredentialsSupplier(Suppliers.ofInstance(validCredentials), - new OAuthCredentialsForCredentials("RS256", SERVICE_ACCOUNT_CREDENTIALS), "RS256"); - assertNotNull(supplier.get()); - } -} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/PrivateKeySupplierTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/PrivateKeySupplierTest.java new file mode 100644 index 0000000000..48d9209442 --- /dev/null +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/PrivateKeySupplierTest.java @@ -0,0 +1,83 @@ +/* + * 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.Suppliers.ofInstance; +import static org.jclouds.oauth.v2.functions.PrivateKeySupplier.PrivateKeyForCredentials; +import static org.testng.Assert.assertNotNull; + +import java.io.File; +import java.io.IOException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.security.spec.InvalidKeySpecException; +import java.util.Properties; + +import org.jclouds.domain.Credentials; +import org.jclouds.oauth.v2.OAuthTestUtils; +import org.jclouds.rest.AuthorizationException; +import org.testng.annotations.Test; + +import com.google.common.base.Charsets; +import com.google.common.base.Suppliers; +import com.google.common.io.Files; + +@Test(groups = "unit") +public class PrivateKeySupplierTest { + + /** Test loading the credentials by extracting a pk from a PKCS12 keystore. */ + public void testLoadPKString() throws IOException, NoSuchAlgorithmException, KeyStoreException, CertificateException, + UnrecoverableKeyException, InvalidKeySpecException { + assertNotNull(loadPrivateKey()); + } + + @Test(expectedExceptions = AuthorizationException.class) + public void testAuthorizationExceptionIsThrownOnBadKeys() { + PrivateKeySupplier supplier = new PrivateKeySupplier( + Suppliers.ofInstance(new Credentials("MOMMA", "FileNotFoundCredential")), + new PrivateKeyForCredentials("RS256")); + supplier.get(); + } + + @Test(expectedExceptions = AuthorizationException.class) + public void testGSEChildExceptionsPropagateAsAuthorizationException() { + PrivateKeySupplier supplier = new PrivateKeySupplier(Suppliers.ofInstance(new Credentials("MOMMA", "MIA")), + new PrivateKeyForCredentials("MOMMA")); + supplier.get(); + } + + public void testCredentialsAreLoadedOnRightAlgoAndCredentials() { + Properties propertied = OAuthTestUtils.defaultProperties(new Properties()); + Credentials validCredentials = new Credentials(propertied.getProperty("oauth.identity"), + propertied.getProperty("oauth.credential")); + PrivateKeySupplier supplier = new PrivateKeySupplier(Suppliers.ofInstance(validCredentials), + new PrivateKeyForCredentials("RS256")); + assertNotNull(supplier.get()); + } + + public static PrivateKey loadPrivateKey() + throws IOException, NoSuchAlgorithmException, CertificateException, InvalidKeySpecException { + PrivateKeySupplier supplier = new PrivateKeySupplier(ofInstance(new Credentials("foo", + Files.asCharSource(new File("src/test/resources/testpk.pem"), Charsets.UTF_8).read())), + new PrivateKeyForCredentials("RS256")); + return supplier.get(); + } + +} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/SignerFunctionTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/SignerFunctionTest.java index 2a64822ce6..a1c8a85545 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/SignerFunctionTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/SignerFunctionTest.java @@ -29,9 +29,6 @@ import java.security.spec.InvalidKeySpecException; import org.testng.annotations.Test; -/** - * Tests the SignOrProduceMacForToken - */ @Test(groups = "unit") public class SignerFunctionTest { @@ -50,10 +47,8 @@ public class SignerFunctionTest { public void testSignPayload() throws InvalidKeyException, IOException, NoSuchAlgorithmException, CertificateException, InvalidKeySpecException { SignOrProduceMacForToken signer = new SignOrProduceMacForToken("RS256", - ofInstance(OAuthCredentialsFromPKTest - .loadOAuthCredentials())); - signer.loadSignatureOrMacOrNone(); - byte[] payloadSignature = signer.apply(PAYLOAD.getBytes(UTF_8)); + ofInstance(PrivateKeySupplierTest.loadPrivateKey())); + byte[] payloadSignature = signer.get().apply(PAYLOAD.getBytes(UTF_8)); assertNotNull(payloadSignature); assertEquals(base64Url().omitPadding().encode(payloadSignature), SHA256withRSA_PAYLOAD_SIGNATURE_RESULT); diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java index 255c5c7f65..c3a61feeda 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java @@ -16,20 +16,20 @@ */ package org.jclouds.oauth.v2.handlers; -import org.easymock.IArgumentMatcher; -import org.jclouds.http.HttpCommand; -import org.jclouds.http.HttpRequest; -import org.jclouds.http.HttpResponse; -import org.testng.annotations.Test; - -import java.net.URI; - import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.reportMatcher; import static org.easymock.EasyMock.verify; +import java.net.URI; + +import org.easymock.IArgumentMatcher; +import org.jclouds.http.HttpCommand; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + @Test(groups = "unit") public class OAuthErrorHandlerTest { diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java index ba1c616bcc..0a50dfe363 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java @@ -19,8 +19,7 @@ package org.jclouds.oauth.v2.internal; import static com.google.common.base.Preconditions.checkNotNull; import static org.jclouds.oauth.v2.OAuthTestUtils.setCredential; import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; -import static org.jclouds.oauth.v2.config.OAuthProperties.SCOPES; -import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; +import static org.jclouds.oauth.v2.config.OAuthProperties.JWS_ALG; import java.util.Properties; import java.util.concurrent.TimeUnit; @@ -43,8 +42,8 @@ public class BaseOAuthApiLiveTest extends BaseApiLiveTest { setCredential(props, "oauth.credential"); checkNotNull(setIfTestSystemPropertyPresent(props, "oauth.endpoint"), "test.oauth.endpoint must be set"); checkNotNull(setIfTestSystemPropertyPresent(props, AUDIENCE), "test.jclouds.oauth.audience must be set"); - setIfTestSystemPropertyPresent(props, SCOPES); - setIfTestSystemPropertyPresent(props, SIGNATURE_OR_MAC_ALGORITHM); + setIfTestSystemPropertyPresent(props, "jclouds.oauth.scopes"); + setIfTestSystemPropertyPresent(props, JWS_ALG); return props; } diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java index c88f65f8ee..558d313249 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java @@ -21,7 +21,7 @@ import static com.google.common.base.Preconditions.checkState; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.SECONDS; import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; -import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM; +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 static org.testng.Assert.assertNotNull; @@ -32,8 +32,8 @@ import java.util.Properties; import org.jclouds.apis.BaseApiLiveTest; import org.jclouds.config.ValueOfConfigurationKeyOrNull; +import org.jclouds.oauth.v2.JWSAlgorithms; import org.jclouds.oauth.v2.OAuthApi; -import org.jclouds.oauth.v2.OAuthConstants; import org.jclouds.oauth.v2.domain.Header; import org.jclouds.oauth.v2.domain.Token; import org.jclouds.oauth.v2.domain.TokenRequest; @@ -51,7 +51,7 @@ import com.google.inject.Module; *

    * - oauth.endpoint * - oauth.audience - * - oauth.signature-or-mac-algorithm + * - oauth.jws-alg *

    * - oauth.scopes is provided by the subclass *

    @@ -68,18 +68,16 @@ public abstract class BaseOAuthAuthenticatedApiLiveTest ext public void testAuthenticate() { // obtain the necessary properties from the context - String signatureAlgorithm = checkNotNull(propFunction.apply(SIGNATURE_OR_MAC_ALGORITHM), - SIGNATURE_OR_MAC_ALGORITHM); + String jwsAlg = checkNotNull(propFunction.apply(JWS_ALG), JWS_ALG); - checkState(OAuthConstants.OAUTH_ALGORITHM_NAMES_TO_SIGNATURE_ALGORITHM_NAMES.containsKey(signatureAlgorithm) - , String.format("Algorithm not supported: " + signatureAlgorithm)); + checkState(JWSAlgorithms.supportedAlgs().contains(jwsAlg), "Algorithm not supported: %s", jwsAlg); String audience = checkNotNull(propFunction.apply(AUDIENCE), AUDIENCE); // obtain the scopes from the subclass String scopes = getScopes(); - Header header = Header.create(signatureAlgorithm, "JWT"); + Header header = Header.create(jwsAlg, "JWT"); long now = SECONDS.convert(System.currentTimeMillis(), MILLISECONDS); From 19e2cdd5d2305eaa77b60f3561d5108ba7984053 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Tue, 11 Nov 2014 20:15:56 -0800 Subject: [PATCH 29/33] * Change OAuthScopes into an interface as opposed to boilerplating annotations. * Fixed errors because of boilerplating annotations. --- apis/oauth/README | 2 +- apis/oauth/pom.xml | 4 +- .../oauth/v2/config/OAuthHttpApiModule.java | 5 +- .../jclouds/oauth/v2/config/OAuthModule.java | 7 +-- .../jclouds/oauth/v2/config/OAuthScopes.java | 63 ++++++++++++++----- .../oauth/v2/functions/BuildTokenRequest.java | 25 ++------ .../oauth/v2/binders/TokenBinderTest.java | 29 ++++++--- .../oauth/v2/features/OAuthApiLiveTest.java | 5 +- .../oauth/v2/features/OAuthApiMockTest.java | 15 +++-- .../v2/internal/BaseOAuthApiLiveTest.java | 22 ++++--- 10 files changed, 107 insertions(+), 70 deletions(-) diff --git a/apis/oauth/README b/apis/oauth/README index 1c5f73b455..40b039d991 100644 --- a/apis/oauth/README +++ b/apis/oauth/README @@ -13,4 +13,4 @@ mvn clean install -Plive\ -Dtest.oauth.credential=\ -Dtest.oauth.endpoint=https://accounts.google.com/o/oauth2/token\ -Dtest.jclouds.oauth.audience=https://accounts.google.com/o/oauth2/token\ - -Dtest.jclouds.oauth.scopes=https://www.googleapis.com/auth/prediction \ No newline at end of file + -Dtest.jclouds.oauth.scope=https://www.googleapis.com/auth/prediction \ No newline at end of file diff --git a/apis/oauth/pom.xml b/apis/oauth/pom.xml index 275ce4bda2..9f83ac8242 100644 --- a/apis/oauth/pom.xml +++ b/apis/oauth/pom.xml @@ -37,7 +37,7 @@ FIX_ME RS256 FIX_ME - FIX_ME + FIX_ME 2 @@ -123,7 +123,7 @@ ${test.oauth.build-version} ${test.jclouds.oauth.jws-alg} ${test.jclouds.oauth.audience} - ${test.jclouds.oauth.scopes} + ${test.jclouds.oauth.scope} 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 index 3bb7c1aaa3..5a1d5d2d44 100644 --- 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 @@ -29,9 +29,7 @@ import com.google.common.base.Supplier; import com.google.common.base.Suppliers; import com.google.inject.Provides; -/** - * OAuth module to when accessing OAuth stand-alone. - */ +/** Api module to when accessing OAuth stand-alone. */ @ConfiguresHttpApi public class OAuthHttpApiModule extends HttpApiModule { @@ -41,5 +39,4 @@ public class OAuthHttpApiModule extends HttpApiModule { protected Supplier provideAuthenticationEndpoint(ProviderMetadata providerMetadata) { return Suppliers.ofInstance(URI.create(providerMetadata.getEndpoint())); } - } 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 e831c0f8f9..e6d5985295 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 @@ -35,6 +35,7 @@ import org.jclouds.oauth.v2.functions.PrivateKeySupplier; import org.jclouds.oauth.v2.functions.SignOrProduceMacForToken; 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; @@ -81,11 +82,7 @@ public class OAuthModule extends AbstractModule { @Provides @Singleton Supplier> signOrProduceMacForToken(@Named(JWS_ALG) String jwsAlg, Provider in) { if (jwsAlg.equals(NONE)) { // Current implementation requires we return null on none. - return Suppliers.>ofInstance(new Function() { - @Override public byte[] apply(byte[] input) { - return null; - } - }); + return (Supplier) Suppliers.ofInstance(Functions.constant(null)); } return Suppliers.memoize(in.get()); } diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java index d4fe7d4a92..d154839bf8 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java @@ -16,26 +16,57 @@ */ 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 java.util.List; -import javax.inject.Qualifier; +import org.jclouds.http.HttpRequest; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; /** - * Used to annotate REST methods/ifaces that use OAuthAuthentication. - *

    - * Sets the scopes for the token request for that particular method. + * Implementations are api-specific, typically routing GET or HEAD requests to a read-only role, and others to a + * read-write one. */ -@Retention(value = RetentionPolicy.RUNTIME) -@Target(value = {ElementType.TYPE, ElementType.METHOD}) -@Qualifier -public @interface OAuthScopes { +public interface OAuthScopes { - /** - * @return the OAuth scopes required to access the resource. - */ - String[] value(); + /** Returns a list of scopes needed to perform the request. */ + List forRequest(HttpRequest input); + @AutoValue public abstract static class SingleScope implements OAuthScopes { + abstract List scopes(); + + public static SingleScope create(String scope) { + return new AutoValue_OAuthScopes_SingleScope(ImmutableList.of(scope)); + } + + @Override public List forRequest(HttpRequest input) { + return scopes(); + } + + SingleScope() { + } + } + + @AutoValue public abstract static class ReadOrWriteScopes implements OAuthScopes { + abstract List readScopes(); + + abstract List writeScopes(); + + public static ReadOrWriteScopes create(String readScope, String writeScope) { + return new AutoValue_OAuthScopes_ReadOrWriteScopes( // + ImmutableList.of(readScope), // + ImmutableList.of(writeScope) // + ); + } + + @Override public List forRequest(HttpRequest input) { + if (input.getMethod().equals("GET") || input.getMethod().equals("HEAD")) { + return readScopes(); + } + return writeScopes(); + } + + ReadOrWriteScopes() { + } + } } 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 4a51954758..51ab318428 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 @@ -16,7 +16,6 @@ */ package org.jclouds.oauth.v2.functions; -import static com.google.common.base.Preconditions.checkState; 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; @@ -35,12 +34,10 @@ 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 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.reflect.Invokable; /** Builds the default token request with the following claims: {@code iss,scope,aud,iat,exp}. */ public class BuildTokenRequest implements Function { @@ -49,13 +46,14 @@ public class BuildTokenRequest implements Function { private final String assertionTargetDescription; private final String signatureAlgorithm; private final Supplier 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 credentialsSupplier, - @Named(PROPERTY_SESSION_INTERVAL) long tokenDuration) { - super(assertionTargetDescription, signatureAlgorithm, credentialsSupplier, tokenDuration); + OAuthScopes scopes, @Named(PROPERTY_SESSION_INTERVAL) long tokenDuration) { + super(assertionTargetDescription, signatureAlgorithm, credentialsSupplier, scopes, tokenDuration); } public long currentTimeSeconds() { @@ -65,10 +63,11 @@ public class BuildTokenRequest implements Function { @Inject BuildTokenRequest(@Named(AUDIENCE) String assertionTargetDescription, @Named(JWS_ALG) String signatureAlgorithm, @Provider Supplier credentialsSupplier, - @Named(PROPERTY_SESSION_INTERVAL) long tokenDuration) { + OAuthScopes scopes, @Named(PROPERTY_SESSION_INTERVAL) long tokenDuration) { this.assertionTargetDescription = assertionTargetDescription; this.signatureAlgorithm = signatureAlgorithm; this.credentialsSupplier = credentialsSupplier; + this.scopes = scopes; this.tokenDuration = tokenDuration; } @@ -77,7 +76,7 @@ public class BuildTokenRequest implements Function { Map claims = new LinkedHashMap(); claims.put("iss", credentialsSupplier.get().identity); - claims.put("scope", getOAuthScopes((GeneratedHttpRequest) request)); + claims.put("scope", ON_COMMA.join(scopes.forRequest(request))); claims.put("aud", assertionTargetDescription); long now = currentTimeSeconds(); @@ -87,18 +86,6 @@ public class BuildTokenRequest implements Function { return TokenRequest.create(header, claims); } - //TODO: Remove and switch to a request function. - private String getOAuthScopes(GeneratedHttpRequest request) { - Invokable invokable = request.getInvocation().getInvokable(); - OAuthScopes classScopes = invokable.getOwnerType().getRawType().getAnnotation(OAuthScopes.class); - OAuthScopes methodScopes = invokable.getAnnotation(OAuthScopes.class); - checkState(classScopes != null || methodScopes != null, "Api interface or method should be annotated " // - + "with OAuthScopes specifying required permissions. Api interface: %s, Method: %s", // - invokable.getOwnerType(), invokable.getName()); - OAuthScopes scopes = methodScopes != null ? methodScopes : classScopes; - return ON_COMMA.join(scopes.value()); - } - long currentTimeSeconds() { return System.currentTimeMillis() / 1000; } diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/binders/TokenBinderTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/binders/TokenBinderTest.java index 2f56aafc00..93042f400a 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/binders/TokenBinderTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/binders/TokenBinderTest.java @@ -25,29 +25,31 @@ import static org.testng.Assert.assertTrue; import java.io.IOException; import java.util.Map; -import org.jclouds.ContextBuilder; import org.jclouds.http.HttpRequest; -import org.jclouds.oauth.v2.OAuthApiMetadata; -import org.jclouds.oauth.v2.OAuthTestUtils; +import org.jclouds.json.config.GsonModule; import org.jclouds.oauth.v2.domain.Header; import org.jclouds.oauth.v2.domain.TokenRequest; import org.jclouds.util.Strings2; import org.testng.annotations.Test; +import com.google.common.base.Function; +import com.google.common.base.Functions; import com.google.common.base.Splitter; +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; +import com.google.inject.Binder; +import com.google.inject.Guice; +import com.google.inject.Module; +import com.google.inject.Provides; @Test(groups = "unit", testName = "OAuthTokenBinderTest") public class TokenBinderTest { public static final String STRING_THAT_GENERATES_URL_UNSAFE_BASE64_ENCODING = "§1234567890'+±!\"#$%&/()" + - "=?*qwertyuiopº´WERTYUIOPªàsdfghjklç~ASDFGHJKLÇ^ZXCVBNM;:_@€"; + "=?*qwertyuiopº´WERTYUIOPªàsdfghjklç~ASDFGHJKLÇ^ZXCVBNM;:_@€"; public void testPayloadIsUrlSafe() throws IOException { - TokenBinder tokenRequestFormat = ContextBuilder.newBuilder(new OAuthApiMetadata()).overrides - (OAuthTestUtils.defaultProperties(null)).build().utils() - .injector().getInstance(TokenBinder.class); Header header = Header.create("a", "b"); Map claims = ImmutableMap.builder() @@ -56,7 +58,7 @@ public class TokenBinderTest { .put("ist", STRING_THAT_GENERATES_URL_UNSAFE_BASE64_ENCODING).build(); TokenRequest tokenRequest = TokenRequest.create(header, claims); - HttpRequest request = tokenRequestFormat.bindToRequest( + HttpRequest request = tokenBinder.bindToRequest( HttpRequest.builder().method("GET").endpoint("http://localhost").build(), tokenRequest); assertNotNull(request.getPayload()); @@ -71,4 +73,13 @@ public class TokenBinderTest { assertTrue(!payload.contains("+")); assertTrue(!payload.contains("/")); } + + private final TokenBinder tokenBinder = Guice.createInjector(new GsonModule(), new Module() { + @Override public void configure(Binder binder) { + } + + @Provides Supplier> signer() { + return (Supplier) Suppliers.ofInstance(Functions.constant(null)); + } + }).getInstance(TokenBinder.class); } diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java index a48b725c7d..cc83f8ba63 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java @@ -65,14 +65,13 @@ public class OAuthApiLiveTest extends BaseOAuthApiLiveTest { Header header = Header.create(jwsAlg, "JWT"); - String scopes = getMandatoryProperty(properties, "jclouds.oauth.scopes"); String audience = getMandatoryProperty(properties, AUDIENCE); - long now = nowInSeconds(); + long now = System.currentTimeMillis() / 1000; Map claims = ImmutableMap.builder() .put("iss", identity) - .put("scope", scopes) + .put("scope", scope) .put("aud", audience) .put(EXPIRATION_TIME, now + 3600) .put(ISSUED_AT, now).build(); diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiMockTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiMockTest.java index f76a360946..febaee751a 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiMockTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiMockTest.java @@ -37,6 +37,8 @@ import org.jclouds.concurrent.config.ExecutorServiceModule; import org.jclouds.oauth.v2.OAuthApi; import org.jclouds.oauth.v2.OAuthApiMetadata; import org.jclouds.oauth.v2.OAuthTestUtils; +import org.jclouds.oauth.v2.config.OAuthScopes; +import org.jclouds.oauth.v2.config.OAuthScopes.SingleScope; import org.jclouds.oauth.v2.domain.Header; import org.jclouds.oauth.v2.domain.Token; import org.jclouds.oauth.v2.domain.TokenRequest; @@ -46,6 +48,7 @@ import com.google.common.base.Joiner; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.io.BaseEncoding; +import com.google.inject.Binder; import com.google.inject.Module; import com.squareup.okhttp.mockwebserver.MockResponse; import com.squareup.okhttp.mockwebserver.MockWebServer; @@ -53,19 +56,19 @@ import com.squareup.okhttp.mockwebserver.RecordedRequest; @Test(groups = "unit", testName = "OAuthApiMockTest") public class OAuthApiMockTest { + private static final String SCOPE = "https://www.googleapis.com/auth/prediction"; private static final String header = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}"; private static final String claims = "{\"iss\":\"761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer" + - ".gserviceaccount.com\"," + - "\"scope\":\"https://www.googleapis.com/auth/prediction\",\"aud\":\"https://accounts.google" + + ".gserviceaccount.com\",\"scope\":\"" + SCOPE + "\",\"aud\":\"https://accounts.google" + ".com/o/oauth2/token\",\"exp\":1328573381,\"iat\":1328569781}"; private static final Token TOKEN = Token.create("1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M", "Bearer", 3600); private static final Map CLAIMS = ImmutableMap.builder() .put("iss", "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com") - .put("scope", "https://www.googleapis.com/auth/prediction") + .put("scope", SCOPE) .put("aud", "https://accounts.google.com/o/oauth2/token") .put(EXPIRATION_TIME, 1328573381) .put(ISSUED_AT, 1328569781).build(); @@ -113,7 +116,11 @@ public class OAuthApiMockTest { .credentials("foo", toStringAndClose(OAuthTestUtils.class.getResourceAsStream("/testpk.pem"))) .endpoint(url.toString()) .overrides(overrides) - .modules(ImmutableSet.of(new ExecutorServiceModule(sameThreadExecutor()))) + .modules(ImmutableSet.of(new ExecutorServiceModule(sameThreadExecutor()), new Module() { + @Override public void configure(Binder binder) { + binder.bind(OAuthScopes.class).toInstance(SingleScope.create(SCOPE)); + } + })) .buildApi(OAuthApi.class); } } diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java index 0a50dfe363..2421d1660d 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java @@ -20,36 +20,44 @@ import static com.google.common.base.Preconditions.checkNotNull; import static org.jclouds.oauth.v2.OAuthTestUtils.setCredential; 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.config.OAuthScopes.SingleScope; import java.util.Properties; -import java.util.concurrent.TimeUnit; import org.jclouds.apis.BaseApiLiveTest; import org.jclouds.oauth.v2.OAuthApi; +import org.jclouds.oauth.v2.config.OAuthScopes; import org.testng.annotations.Test; +import com.google.common.collect.ImmutableList; +import com.google.inject.Binder; +import com.google.inject.Module; @Test(groups = "live") public class BaseOAuthApiLiveTest extends BaseApiLiveTest { + protected String scope; + public BaseOAuthApiLiveTest() { provider = "oauth"; } - @Override - protected Properties setupProperties() { + @Override protected Properties setupProperties() { Properties props = super.setupProperties(); setCredential(props, "oauth.credential"); checkNotNull(setIfTestSystemPropertyPresent(props, "oauth.endpoint"), "test.oauth.endpoint must be set"); checkNotNull(setIfTestSystemPropertyPresent(props, AUDIENCE), "test.jclouds.oauth.audience must be set"); - setIfTestSystemPropertyPresent(props, "jclouds.oauth.scopes"); + scope = setIfTestSystemPropertyPresent(props, "jclouds.oauth.scope"); setIfTestSystemPropertyPresent(props, JWS_ALG); return props; } - protected long nowInSeconds() { - return TimeUnit.SECONDS.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS); + @Override protected Iterable setupModules() { + return ImmutableList.builder().add(new Module() { + @Override public void configure(Binder binder) { + binder.bind(OAuthScopes.class).toInstance(SingleScope.create(scope)); + } + }).addAll(super.setupModules()).build(); } - } From a35d73c6d0634607804026ded2ea0c9ba2256015 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Thu, 13 Nov 2014 10:00:30 -0800 Subject: [PATCH 30/33] Dedupe code between google cloud products. --- .../oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java | 1 + 1 file changed, 1 insertion(+) diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java index ed512d360c..e5ec5ec68d 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthTestUtils.java @@ -55,6 +55,7 @@ public class OAuthTestUtils { return properties; } + // TODO: move to jclouds-core public static String setCredential(Properties overrides, String key) { String val = null; String credentialFromFile = null; From 46a7351a8a2c38bc191a52d8f909976d37142cb8 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Mon, 17 Nov 2014 19:50:48 -0800 Subject: [PATCH 31/33] * 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. --- apis/oauth/pom.xml | 1 - .../jclouds/oauth/v2/AuthorizationApi.java} | 36 +++--- .../org/jclouds/oauth/v2/JWSAlgorithms.java | 75 ------------ .../java/org/jclouds/oauth/v2/OAuthApi.java | 61 ---------- .../jclouds/oauth/v2/OAuthApiMetadata.java | 83 ------------- .../jclouds/oauth/v2/binders/TokenBinder.java | 77 ------------ .../config/{OAuth.java => Authorization.java} | 7 +- .../v2/config/OAuthAuthenticationModule.java | 46 ------- .../oauth/v2/config/OAuthHttpApiModule.java | 42 ------- .../jclouds/oauth/v2/config/OAuthModule.java | 78 ++++-------- .../oauth/v2/config/OAuthProperties.java | 10 +- .../PrivateKeySupplier.java | 23 ++-- .../org/jclouds/oauth/v2/domain/Claims.java | 35 ++++-- .../org/jclouds/oauth/v2/domain/Header.java | 41 ------- .../jclouds/oauth/v2/domain/TokenRequest.java | 31 ----- ...r.java => BearerTokenFromCredentials.java} | 8 +- .../oauth/v2/filters/JWTBearerTokenFlow.java | 113 ++++++++++++++++++ .../oauth/v2/filters/OAuthAuthenticator.java | 51 -------- ...enticationFilter.java => OAuthFilter.java} | 8 +- .../oauth/v2/functions/BuildTokenRequest.java | 92 -------------- .../oauth/v2/functions/ClaimsToAssertion.java | 87 ++++++++++++++ .../oauth/v2/functions/FetchToken.java | 38 ------ .../functions/SignOrProduceMacForToken.java | 101 ---------------- .../oauth/v2/handlers/OAuthErrorHandler.java | 58 --------- .../oauth/v2/AuthorizationApiLiveTest.java | 94 +++++++++++++++ ...est.java => AuthorizationApiMockTest.java} | 53 ++++---- .../oauth/v2/OAuthApiMetadataTest.java | 39 ------ .../oauth/v2/binders/TokenBinderTest.java | 85 ------------- .../PrivateKeySupplierTest.java | 30 ++--- .../oauth/v2/features/OAuthApiLiveTest.java | 84 ------------- ...onTest.java => ClaimsToAssertionTest.java} | 24 ++-- .../v2/handlers/OAuthErrorHandlerTest.java | 92 -------------- .../oauth/v2/internal/Base64UrlSafeTest.java | 40 ------- .../v2/internal/BaseOAuthApiLiveTest.java | 63 ---------- .../BaseOAuthAuthenticatedApiLiveTest.java | 112 ----------------- .../src/test/resources/tokenResponse.json | 5 - 36 files changed, 429 insertions(+), 1494 deletions(-) rename apis/oauth/src/{test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java => main/java/org/jclouds/oauth/v2/AuthorizationApi.java} (53%) delete mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/JWSAlgorithms.java delete mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApi.java delete mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java delete mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/binders/TokenBinder.java rename apis/oauth/src/main/java/org/jclouds/oauth/v2/config/{OAuth.java => Authorization.java} (90%) delete mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthAuthenticationModule.java delete mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthHttpApiModule.java rename apis/oauth/src/main/java/org/jclouds/oauth/v2/{functions => config}/PrivateKeySupplier.java (83%) delete mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Header.java delete mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequest.java rename apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/{BearerTokenAuthenticator.java => BearerTokenFromCredentials.java} (80%) create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/JWTBearerTokenFlow.java delete mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java rename apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/{OAuthAuthenticationFilter.java => OAuthFilter.java} (83%) delete mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java create mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/ClaimsToAssertion.java delete mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java delete mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java delete mode 100644 apis/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java create mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/AuthorizationApiLiveTest.java rename apis/oauth/src/test/java/org/jclouds/oauth/v2/{features/OAuthApiMockTest.java => AuthorizationApiMockTest.java} (75%) delete mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java delete mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/binders/TokenBinderTest.java rename apis/oauth/src/test/java/org/jclouds/oauth/v2/{functions => config}/PrivateKeySupplierTest.java (66%) delete mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java rename apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/{SignerFunctionTest.java => ClaimsToAssertionTest.java} (72%) delete mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java delete mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/Base64UrlSafeTest.java delete mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java delete mode 100644 apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java delete mode 100644 apis/oauth/src/test/resources/tokenResponse.json diff --git a/apis/oauth/pom.xml b/apis/oauth/pom.xml index 9f83ac8242..f978213481 100644 --- a/apis/oauth/pom.xml +++ b/apis/oauth/pom.xml @@ -35,7 +35,6 @@ FIX_ME FIX_ME FIX_ME - RS256 FIX_ME FIX_ME 2 diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/AuthorizationApi.java similarity index 53% rename from apis/oauth/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java rename to apis/oauth/src/main/java/org/jclouds/oauth/v2/AuthorizationApi.java index 416ec5ef18..0a9d4533f2 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/parse/ParseTokenTest.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/AuthorizationApi.java @@ -14,27 +14,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jclouds.oauth.v2.parse; +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.json.BaseItemParserTest; +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.testng.annotations.Test; +import org.jclouds.rest.annotations.Endpoint; +import org.jclouds.rest.annotations.FormParams; +import org.jclouds.rest.annotations.ParamParser; -@Test(groups = "unit", testName = "ParseTokenTest") -public class ParseTokenTest extends BaseItemParserTest { - - @Override - public String resource() { - return "/tokenResponse.json"; - } - - @Override +/** + * Binds to an OAuth2 authorization endpoint. + */ +@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) - public Token expected() { - return Token.create("1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M", "Bearer", 3600); - } + Token authorize(@FormParam("assertion") @ParamParser(ClaimsToAssertion.class) Claims claims); } 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 072fc531d8..0000000000 --- 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 - *

    - * We only support required - * or recommended algorithms, 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 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> ALG_TO_SIGNATURE_ALG_AND_KEY_FACTORY = ImmutableList.>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 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() { - } -} 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 770e5e824c..0000000000 --- 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. - *

    - * 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; -} 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 66f61bbf24..0000000000 --- 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 { - - @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 { - - protected Builder() { - id("oauth") - .name("OAuth API") - .identityName("service_account") - .credentialName("service_key") - .documentation(URI.create("TODO")) - .version("2") - .defaultProperties(OAuthApiMetadata.defaultProperties()) - .defaultModules(ImmutableSet.>of(OAuthModule.class, OAuthHttpApiModule.class)); - } - - @Override - public OAuthApiMetadata build() { - return new OAuthApiMetadata(this); - } - - @Override - protected Builder self() { - return this; - } - } -} 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 078200088a..0000000000 --- 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: - *

      - *
    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 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> signer; - private final Json json; - - @Inject TokenBinder(Supplier> signer, Json json) { - this.signer = signer; - this.json = json; - } - - @Override public 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. builder() - .put(GRANT_TYPE_FORM_PARAM, GRANT_TYPE_JWT_BEARER) - .put(ASSERTION_FORM_PARAM, assertion).build()); - - return (R) request.toBuilder().payload(payload).build(); - } -} 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/Authorization.java similarity index 90% rename from apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuth.java rename to apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authorization.java index 6255e50442..cefc5acc32 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuth.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authorization.java @@ -23,13 +23,8 @@ 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 { +public @interface Authorization { } 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 4d238f123d..0000000000 --- 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 oauthEndpoint(@Named("oauth.endpoint") String endpoint) { - return Suppliers.ofInstance(URI.create(endpoint)); - } -} 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 5a1d5d2d44..0000000000 --- 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 { - - @Provides - @Singleton - @OAuth - protected Supplier provideAuthenticationEndpoint(ProviderMetadata providerMetadata) { - return Suppliers.ofInstance(URI.create(providerMetadata.getEndpoint())); - } -} 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 e6d5985295..8a3568ce99 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>() {}).to(BuildTokenRequest.class); - bind(new TypeLiteral>() {}).to(FetchToken.class); - bind(new TypeLiteral>() {}).annotatedWith(OAuth.class).to(PrivateKeySupplier.class); + bind(new TypeLiteral>() {}).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 provideAccessCache(Function 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> signOrProduceMacForToken(@Named(JWS_ALG) String jwsAlg, - Provider 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 oauthEndpoint(@javax.inject.Named("oauth.endpoint") String endpoint) { + return Suppliers.ofInstance(URI.create(endpoint)); } @Singleton public static class CredentialTypeFromPropertyOrDefault implements Provider { @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; 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 197bc310c3..7faed0cbad 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 doc + * @see doc */ 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() { + } } 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/config/PrivateKeySupplier.java similarity index 83% rename from apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/PrivateKeySupplier.java rename to apis/oauth/src/main/java/org/jclouds/oauth/v2/config/PrivateKeySupplier.java index cbdad5ef45..4873dc9937 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/PrivateKeySupplier.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/PrivateKeySupplier.java @@ -14,27 +14,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jclouds.oauth.v2.functions; +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.oauth.v2.config.OAuthProperties.JWS_ALG; 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.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; @@ -46,11 +44,11 @@ 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. + * 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 -public final class PrivateKeySupplier implements Supplier { +final class PrivateKeySupplier implements Supplier { private final Supplier creds; private final LoadingCache keyCache; @@ -68,17 +66,14 @@ public final class PrivateKeySupplier implements Supplier { */ @VisibleForTesting static final class PrivateKeyForCredentials extends CacheLoader { - 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); + 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) { 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 07b03f646e..9087acd37c 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 registered list */ -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() { } } 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 9cdd924fa8..0000000000 --- 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 doc - */ -@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); - } -} 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 b08a20ba90..0000000000 --- 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 claimSet(); - - public static TokenRequest create(Header header, Map claims) { - return new AutoValue_TokenRequest(header, claims); - } -} 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/BearerTokenFromCredentials.java similarity index 80% rename from apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenAuthenticator.java rename to apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenFromCredentials.java index 3d7d92d03b..61eacf1c61 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/BearerTokenFromCredentials.java @@ -27,10 +27,14 @@ import org.jclouds.location.Provider; import com.google.common.base.Supplier; -public final class BearerTokenAuthenticator implements OAuthAuthenticationFilter { +/** + * 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 creds; - @Inject BearerTokenAuthenticator(@Provider Supplier creds) { + @Inject BearerTokenFromCredentials(@Provider Supplier creds) { this.creds = creds; } 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 0000000000..466c8e3e88 --- /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. + * + *

    Cache

    + * 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 credentialsSupplier; + private final OAuthScopes scopes; + private final long tokenDuration; + private final LoadingCache tokenCache; + + public static class TestJWTBearerTokenFlow extends JWTBearerTokenFlow { + + @Inject TestJWTBearerTokenFlow(AuthorizeToken loader, @Named(PROPERTY_SESSION_INTERVAL) long tokenDuration, + @Named(AUDIENCE) String audience, @Provider Supplier 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 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 { + 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; + } +} 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 cb858b50f7..0000000000 --- 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. - *

    - * TODO when we're able to use the OAuthAuthentication an this should be used automatically - */ -public final class OAuthAuthenticator implements OAuthAuthenticationFilter { - - private Function tokenRequestBuilder; - private Function tokenFetcher; - - @Inject OAuthAuthenticator(Function tokenRequestBuilder, - LoadingCache 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(); - } -} 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/OAuthFilter.java similarity index 83% rename from apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticationFilter.java rename to apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthFilter.java index e6e5714b85..fa07d1e0e1 100644 --- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticationFilter.java +++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthFilter.java @@ -18,10 +18,6 @@ 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 { - +/** Indicates use of auth mechanism according to {@link org.jclouds.oauth.v2.config.OAuthProperties#CREDENTIAL_TYPE). */ +public interface OAuthFilter extends HttpRequestFilter { } 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 51ab318428..0000000000 --- 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 { - private static final Joiner ON_COMMA = Joiner.on(","); - - private final String assertionTargetDescription; - private final String signatureAlgorithm; - private final Supplier 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 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 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 claims = new LinkedHashMap(); - 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; - } -} 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 0000000000..d40f12e0d0 --- /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 { + private static final List SUPPORTED_ALGS = ImmutableList.of("RS256", "none"); + + private final Supplier privateKey; + private final Json json; + private final String alg; + + @Inject ClaimsToAssertion(@Named(JWS_ALG) String alg, @Authorization Supplier 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); + } + } +} 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 1a02cab748..0000000000 --- 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 { - - private final OAuthApi oAuthApi; - - @Inject FetchToken(OAuthApi oAuthApi) { - this.oAuthApi = oAuthApi; - } - - @Override public Token apply(TokenRequest input) { - return this.oAuthApi.authenticate(input); - } -} 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 fd827b1751..0000000000 --- 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> { - - private final String macOrSignature; - private final Supplier credentials; - - @Inject SignOrProduceMacForToken(@Named(JWS_ALG) String jwsAlg, @OAuth Supplier credentials) { - this.macOrSignature = macOrSignature(jwsAlg); - this.credentials = credentials; - } - - @Override public Function 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 { - - 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 { - - 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); - } - } - } -} 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 ddc88a81fe..0000000000 --- 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); - } -} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/AuthorizationApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/AuthorizationApiLiveTest.java new file mode 100644 index 0000000000..5002307a85 --- /dev/null +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/AuthorizationApiLiveTest.java @@ -0,0 +1,94 @@ +/* + * 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.checkNotNull; +import static org.jclouds.oauth.v2.OAuthTestUtils.setCredential; +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.config.OAuthScopes.SingleScope; +import static org.jclouds.providers.AnonymousProviderMetadata.forApiOnEndpoint; +import static org.testng.Assert.assertNotNull; + +import java.util.Properties; + +import org.jclouds.apis.BaseApiLiveTest; +import org.jclouds.oauth.v2.config.OAuthModule; +import org.jclouds.oauth.v2.config.OAuthScopes; +import org.jclouds.oauth.v2.domain.Claims; +import org.jclouds.oauth.v2.domain.Token; +import org.jclouds.providers.ProviderMetadata; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; +import com.google.inject.Binder; +import com.google.inject.Module; +import com.google.inject.name.Names; + +@Test(groups = "live", singleThreaded = true) +public class AuthorizationApiLiveTest extends BaseApiLiveTest { + + private final String jwsAlg = "RS256"; + private String scope; + private String audience; + + public AuthorizationApiLiveTest() { + provider = "oauth"; + } + + public void authenticateJWTToken() throws Exception { + long now = System.currentTimeMillis() / 1000; + Claims claims = Claims.create( + identity, // iss + scope, // scope + audience, // aud + now + 3600, // exp + now // iat + ); + + Token token = api.authorize(claims); + + assertNotNull(token, "no token when authorizing " + claims); + } + + /** OAuth isn't registered as a provider intentionally, so we fake one. */ + @Override protected ProviderMetadata createProviderMetadata() { + return forApiOnEndpoint(AuthorizationApi.class, endpoint).toBuilder().id("oauth").build(); + } + + @Override protected Properties setupProperties() { + Properties props = super.setupProperties(); + props.setProperty(JWS_ALG, jwsAlg); + credential = setCredential(props, "oauth.credential"); + audience = checkNotNull(setIfTestSystemPropertyPresent(props, AUDIENCE), "test.jclouds.oauth.audience"); + scope = checkNotNull(setIfTestSystemPropertyPresent(props, "jclouds.oauth.scope"), "test.jclouds.oauth.scope"); + return props; + } + + @Override protected Iterable setupModules() { + return ImmutableList.builder() // + .add(new OAuthModule()) // + .add(new Module() { + @Override public void configure(Binder binder) { + // ContextBuilder erases oauth.endpoint, as that's the same name as the provider key. + binder.bindConstant().annotatedWith(Names.named("oauth.endpoint")).to(endpoint); + binder.bind(OAuthScopes.class).toInstance(SingleScope.create(scope)); + } + }).addAll(super.setupModules()).build(); + } +} + diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiMockTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/AuthorizationApiMockTest.java similarity index 75% rename from apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiMockTest.java rename to apis/oauth/src/test/java/org/jclouds/oauth/v2/AuthorizationApiMockTest.java index febaee751a..0d0909011a 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiMockTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/AuthorizationApiMockTest.java @@ -14,38 +14,35 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jclouds.oauth.v2.features; +package org.jclouds.oauth.v2; import static com.google.common.base.Charsets.UTF_8; import static com.google.common.io.BaseEncoding.base64Url; import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor; import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static org.jclouds.Constants.PROPERTY_MAX_RETRIES; +import static org.jclouds.oauth.v2.config.CredentialType.P12_PRIVATE_KEY_CREDENTIALS; import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; -import static org.jclouds.oauth.v2.domain.Claims.EXPIRATION_TIME; -import static org.jclouds.oauth.v2.domain.Claims.ISSUED_AT; +import static org.jclouds.oauth.v2.config.OAuthProperties.CREDENTIAL_TYPE; +import static org.jclouds.oauth.v2.config.OAuthProperties.JWS_ALG; import static org.jclouds.util.Strings2.toStringAndClose; import static org.testng.Assert.assertEquals; import java.io.IOException; import java.net.URL; -import java.util.Map; import java.util.Properties; import org.jclouds.ContextBuilder; import org.jclouds.concurrent.config.ExecutorServiceModule; -import org.jclouds.oauth.v2.OAuthApi; -import org.jclouds.oauth.v2.OAuthApiMetadata; -import org.jclouds.oauth.v2.OAuthTestUtils; +import org.jclouds.oauth.v2.config.OAuthModule; import org.jclouds.oauth.v2.config.OAuthScopes; import org.jclouds.oauth.v2.config.OAuthScopes.SingleScope; -import org.jclouds.oauth.v2.domain.Header; +import org.jclouds.oauth.v2.domain.Claims; import org.jclouds.oauth.v2.domain.Token; -import org.jclouds.oauth.v2.domain.TokenRequest; +import org.jclouds.rest.AnonymousHttpApiMetadata; import org.testng.annotations.Test; import com.google.common.base.Joiner; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.io.BaseEncoding; import com.google.inject.Binder; @@ -55,7 +52,7 @@ import com.squareup.okhttp.mockwebserver.MockWebServer; import com.squareup.okhttp.mockwebserver.RecordedRequest; @Test(groups = "unit", testName = "OAuthApiMockTest") -public class OAuthApiMockTest { +public class AuthorizationApiMockTest { private static final String SCOPE = "https://www.googleapis.com/auth/prediction"; private static final String header = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}"; @@ -66,14 +63,13 @@ public class OAuthApiMockTest { private static final Token TOKEN = Token.create("1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M", "Bearer", 3600); - private static final Map CLAIMS = ImmutableMap.builder() - .put("iss", "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com") - .put("scope", SCOPE) - .put("aud", "https://accounts.google.com/o/oauth2/token") - .put(EXPIRATION_TIME, 1328573381) - .put(ISSUED_AT, 1328569781).build(); - - private static final Header HEADER = Header.create("RS256", "JWT"); + private static final Claims CLAIMS = Claims.create( + "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com", // iss + SCOPE, // scope + "https://accounts.google.com/o/oauth2/token", // aud + 1328573381, // exp + 1328569781 // iat + ); public void testGenerateJWTRequest() throws Exception { MockWebServer server = new MockWebServer(); @@ -84,9 +80,9 @@ public class OAuthApiMockTest { "}")); server.play(); - OAuthApi api = api(server.getUrl("/")); + AuthorizationApi api = api(server.getUrl("/")); - assertEquals(api.authenticate(TokenRequest.create(HEADER, CLAIMS)), TOKEN); + assertEquals(api.authorize(CLAIMS), TOKEN); RecordedRequest request = server.takeRequest(); assertEquals(request.getMethod(), "POST"); @@ -107,20 +103,23 @@ public class OAuthApiMockTest { private final BaseEncoding encoding = base64Url().omitPadding(); - private OAuthApi api(URL url) throws IOException { + private AuthorizationApi api(URL url) throws IOException { Properties overrides = new Properties(); - overrides.put(AUDIENCE, "https://accounts.google.com/o/oauth2/token"); - overrides.put(PROPERTY_MAX_RETRIES, "1"); + overrides.setProperty("oauth.endpoint", url.toString()); + overrides.setProperty(JWS_ALG, "RS256"); + overrides.setProperty(CREDENTIAL_TYPE, P12_PRIVATE_KEY_CREDENTIALS.toString()); + overrides.setProperty(AUDIENCE, "https://accounts.google.com/o/oauth2/token"); + overrides.setProperty(PROPERTY_MAX_RETRIES, "1"); - return ContextBuilder.newBuilder(new OAuthApiMetadata()) + return ContextBuilder.newBuilder(AnonymousHttpApiMetadata.forApi(AuthorizationApi.class)) .credentials("foo", toStringAndClose(OAuthTestUtils.class.getResourceAsStream("/testpk.pem"))) .endpoint(url.toString()) .overrides(overrides) - .modules(ImmutableSet.of(new ExecutorServiceModule(sameThreadExecutor()), new Module() { + .modules(ImmutableSet.of(new ExecutorServiceModule(sameThreadExecutor()), new OAuthModule(), new Module() { @Override public void configure(Binder binder) { binder.bind(OAuthScopes.class).toInstance(SingleScope.create(SCOPE)); } })) - .buildApi(OAuthApi.class); + .buildApi(AuthorizationApi.class); } } diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java deleted file mode 100644 index 3bd0456732..0000000000 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/OAuthApiMetadataTest.java +++ /dev/null @@ -1,39 +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 org.jclouds.View; -import org.jclouds.apis.internal.BaseApiMetadataTest; -import org.testng.annotations.Test; - -import com.google.common.collect.ImmutableSet; -import com.google.common.reflect.TypeToken; - -/** - * Tests that OAuthApiMetadata is properly registered in ServiceLoader - *

    - *

    - * META-INF/services/org.jclouds.apis.ApiMetadata
    - * 
    - */ -@Test(groups = "unit") -public class OAuthApiMetadataTest extends BaseApiMetadataTest { - - public OAuthApiMetadataTest() { - super(new OAuthApiMetadata(), ImmutableSet.>of()); - } -} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/binders/TokenBinderTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/binders/TokenBinderTest.java deleted file mode 100644 index 93042f400a..0000000000 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/binders/TokenBinderTest.java +++ /dev/null @@ -1,85 +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 org.jclouds.oauth.v2.domain.Claims.EXPIRATION_TIME; -import static org.jclouds.oauth.v2.domain.Claims.ISSUED_AT; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertSame; -import static org.testng.Assert.assertTrue; - -import java.io.IOException; -import java.util.Map; - -import org.jclouds.http.HttpRequest; -import org.jclouds.json.config.GsonModule; -import org.jclouds.oauth.v2.domain.Header; -import org.jclouds.oauth.v2.domain.TokenRequest; -import org.jclouds.util.Strings2; -import org.testng.annotations.Test; - -import com.google.common.base.Function; -import com.google.common.base.Functions; -import com.google.common.base.Splitter; -import com.google.common.base.Supplier; -import com.google.common.base.Suppliers; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Iterables; -import com.google.inject.Binder; -import com.google.inject.Guice; -import com.google.inject.Module; -import com.google.inject.Provides; - -@Test(groups = "unit", testName = "OAuthTokenBinderTest") -public class TokenBinderTest { - public static final String STRING_THAT_GENERATES_URL_UNSAFE_BASE64_ENCODING = "§1234567890'+±!\"#$%&/()" + - "=?*qwertyuiopº´WERTYUIOPªàsdfghjklç~ASDFGHJKLÇ^ZXCVBNM;:_@€"; - - public void testPayloadIsUrlSafe() throws IOException { - Header header = Header.create("a", "b"); - - Map claims = ImmutableMap.builder() - .put(ISSUED_AT, 0) - .put(EXPIRATION_TIME, 0) - .put("ist", STRING_THAT_GENERATES_URL_UNSAFE_BASE64_ENCODING).build(); - - TokenRequest tokenRequest = TokenRequest.create(header, claims); - HttpRequest request = tokenBinder.bindToRequest( - HttpRequest.builder().method("GET").endpoint("http://localhost").build(), tokenRequest); - - assertNotNull(request.getPayload()); - - String payload = Strings2.toStringAndClose(request.getPayload().getInput()); - - // make sure the paylod is in the format {header}.{claims}.{signature} - Iterable parts = Splitter.on(".").split(payload); - - assertSame(Iterables.size(parts), 3); - - assertTrue(!payload.contains("+")); - assertTrue(!payload.contains("/")); - } - - private final TokenBinder tokenBinder = Guice.createInjector(new GsonModule(), new Module() { - @Override public void configure(Binder binder) { - } - - @Provides Supplier> signer() { - return (Supplier) Suppliers.ofInstance(Functions.constant(null)); - } - }).getInstance(TokenBinder.class); -} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/PrivateKeySupplierTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/config/PrivateKeySupplierTest.java similarity index 66% rename from apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/PrivateKeySupplierTest.java rename to apis/oauth/src/test/java/org/jclouds/oauth/v2/config/PrivateKeySupplierTest.java index 48d9209442..088c9028c1 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/PrivateKeySupplierTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/config/PrivateKeySupplierTest.java @@ -14,24 +14,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jclouds.oauth.v2.functions; +package org.jclouds.oauth.v2.config; import static com.google.common.base.Suppliers.ofInstance; -import static org.jclouds.oauth.v2.functions.PrivateKeySupplier.PrivateKeyForCredentials; import static org.testng.Assert.assertNotNull; import java.io.File; -import java.io.IOException; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; -import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateException; -import java.security.spec.InvalidKeySpecException; import java.util.Properties; import org.jclouds.domain.Credentials; import org.jclouds.oauth.v2.OAuthTestUtils; +import org.jclouds.oauth.v2.config.PrivateKeySupplier.PrivateKeyForCredentials; import org.jclouds.rest.AuthorizationException; import org.testng.annotations.Test; @@ -43,8 +37,7 @@ import com.google.common.io.Files; public class PrivateKeySupplierTest { /** Test loading the credentials by extracting a pk from a PKCS12 keystore. */ - public void testLoadPKString() throws IOException, NoSuchAlgorithmException, KeyStoreException, CertificateException, - UnrecoverableKeyException, InvalidKeySpecException { + public void testLoadPKString() throws Exception { assertNotNull(loadPrivateKey()); } @@ -52,14 +45,7 @@ public class PrivateKeySupplierTest { public void testAuthorizationExceptionIsThrownOnBadKeys() { PrivateKeySupplier supplier = new PrivateKeySupplier( Suppliers.ofInstance(new Credentials("MOMMA", "FileNotFoundCredential")), - new PrivateKeyForCredentials("RS256")); - supplier.get(); - } - - @Test(expectedExceptions = AuthorizationException.class) - public void testGSEChildExceptionsPropagateAsAuthorizationException() { - PrivateKeySupplier supplier = new PrivateKeySupplier(Suppliers.ofInstance(new Credentials("MOMMA", "MIA")), - new PrivateKeyForCredentials("MOMMA")); + new PrivateKeyForCredentials()); supplier.get(); } @@ -68,16 +54,14 @@ public class PrivateKeySupplierTest { Credentials validCredentials = new Credentials(propertied.getProperty("oauth.identity"), propertied.getProperty("oauth.credential")); PrivateKeySupplier supplier = new PrivateKeySupplier(Suppliers.ofInstance(validCredentials), - new PrivateKeyForCredentials("RS256")); + new PrivateKeyForCredentials()); assertNotNull(supplier.get()); } - public static PrivateKey loadPrivateKey() - throws IOException, NoSuchAlgorithmException, CertificateException, InvalidKeySpecException { + public static PrivateKey loadPrivateKey() throws Exception { PrivateKeySupplier supplier = new PrivateKeySupplier(ofInstance(new Credentials("foo", Files.asCharSource(new File("src/test/resources/testpk.pem"), Charsets.UTF_8).read())), - new PrivateKeyForCredentials("RS256")); + new PrivateKeyForCredentials()); return supplier.get(); } - } diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java deleted file mode 100644 index cc83f8ba63..0000000000 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/features/OAuthApiLiveTest.java +++ /dev/null @@ -1,84 +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.features; - -import static com.google.common.base.Preconditions.checkState; -import static org.jclouds.oauth.v2.OAuthTestUtils.getMandatoryProperty; -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 static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; - -import java.util.Map; -import java.util.Properties; - -import org.jclouds.oauth.v2.JWSAlgorithms; -import org.jclouds.oauth.v2.domain.Header; -import org.jclouds.oauth.v2.domain.Token; -import org.jclouds.oauth.v2.domain.TokenRequest; -import org.jclouds.oauth.v2.internal.BaseOAuthApiLiveTest; -import org.testng.annotations.Test; - -import com.google.common.collect.ImmutableMap; - -/** - * A live test for authentication. Requires the following properties to be set: - * - test.oauth.endpoint - * - test.oauth.identity - * - test.oauth.credential - * - test.jclouds.oauth.audience - * - test.jclouds.oauth.scopes - * - test.jclouds.oauth.jws-alg - */ -@Test(groups = "live", singleThreaded = true) -public class OAuthApiLiveTest extends BaseOAuthApiLiveTest { - - private Properties properties; - - @Override - protected Properties setupProperties() { - properties = super.setupProperties(); - return properties; - } - - @Test(groups = "live", singleThreaded = true) - public void testAuthenticateJWTToken() throws Exception { - assertTrue(properties != null, "properties were not set"); - String jwsAlg = getMandatoryProperty(properties, JWS_ALG); - checkState(JWSAlgorithms.supportedAlgs().contains(jwsAlg), "Algorithm not supported: %s", jwsAlg); - - Header header = Header.create(jwsAlg, "JWT"); - - String audience = getMandatoryProperty(properties, AUDIENCE); - - long now = System.currentTimeMillis() / 1000; - - Map claims = ImmutableMap.builder() - .put("iss", identity) - .put("scope", scope) - .put("aud", audience) - .put(EXPIRATION_TIME, now + 3600) - .put(ISSUED_AT, now).build(); - - TokenRequest tokenRequest = TokenRequest.create(header, claims); - Token token = api.authenticate(tokenRequest); - - assertNotNull(token, "no token when authenticating " + tokenRequest); - } -} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/SignerFunctionTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/ClaimsToAssertionTest.java similarity index 72% rename from apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/SignerFunctionTest.java rename to apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/ClaimsToAssertionTest.java index a1c8a85545..bff9ed09e0 100644 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/SignerFunctionTest.java +++ b/apis/oauth/src/test/java/org/jclouds/oauth/v2/functions/ClaimsToAssertionTest.java @@ -15,22 +15,17 @@ * 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.Suppliers.ofInstance; -import static com.google.common.io.BaseEncoding.base64Url; -import static org.testng.Assert.assertNotNull; -import static org.testng.AssertJUnit.assertEquals; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; -import java.security.spec.InvalidKeySpecException; +import static com.google.common.base.Charsets.UTF_8; +import static com.google.common.io.BaseEncoding.base64Url; +import static org.jclouds.oauth.v2.config.PrivateKeySupplierTest.loadPrivateKey; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; import org.testng.annotations.Test; @Test(groups = "unit") -public class SignerFunctionTest { +public class ClaimsToAssertionTest { private static final String PAYLOAD = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.\n" + "eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZ" + @@ -44,11 +39,8 @@ public class SignerFunctionTest { "I9-nj3oUGd1fQty2k4Lsd-Zdkz6es"; - public void testSignPayload() throws InvalidKeyException, IOException, NoSuchAlgorithmException, - CertificateException, InvalidKeySpecException { - SignOrProduceMacForToken signer = new SignOrProduceMacForToken("RS256", - ofInstance(PrivateKeySupplierTest.loadPrivateKey())); - byte[] payloadSignature = signer.get().apply(PAYLOAD.getBytes(UTF_8)); + public void sha256() throws Exception { + byte[] payloadSignature = ClaimsToAssertion.sha256(loadPrivateKey(), PAYLOAD.getBytes(UTF_8)); assertNotNull(payloadSignature); assertEquals(base64Url().omitPadding().encode(payloadSignature), SHA256withRSA_PAYLOAD_SIGNATURE_RESULT); diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.java deleted file mode 100644 index c3a61feeda..0000000000 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandlerTest.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.handlers; - -import static org.easymock.EasyMock.createMock; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.replay; -import static org.easymock.EasyMock.reportMatcher; -import static org.easymock.EasyMock.verify; - -import java.net.URI; - -import org.easymock.IArgumentMatcher; -import org.jclouds.http.HttpCommand; -import org.jclouds.http.HttpRequest; -import org.jclouds.http.HttpResponse; -import org.testng.annotations.Test; - -@Test(groups = "unit") -public class OAuthErrorHandlerTest { - - @Test - public void test409MakesIllegalStateException() { - assertCodeMakes( - "POST", - URI.create("http://oauth.org"), - 409, - "HTTP/1.1 409 Conflict", - "\"{\"code\":\"InvalidState\",\"message\":\"An incompatible transition has already been queued for this" + - " resource\"}\"", - IllegalStateException.class); - } - - private void assertCodeMakes(String method, URI uri, int statusCode, String message, String content, - Class expected) { - assertCodeMakes(method, uri, statusCode, message, "application/json", content, expected); - } - - private void assertCodeMakes(String method, URI uri, int statusCode, String message, String contentType, - String content, Class expected) { - - OAuthErrorHandler function = new OAuthErrorHandler(); - - HttpCommand command = createMock(HttpCommand.class); - HttpRequest request = HttpRequest.builder().method(method).endpoint(uri).build(); - HttpResponse response = HttpResponse.builder().statusCode(statusCode).message(message).payload(content).build(); - response.getPayload().getContentMetadata().setContentType(contentType); - - expect(command.getCurrentRequest()).andReturn(request).atLeastOnce(); - command.setException(classEq(expected)); - - replay(command); - - function.handleError(command, response); - - verify(command); - } - - public static Exception classEq(final Class in) { - reportMatcher(new IArgumentMatcher() { - - @Override - public void appendTo(StringBuffer buffer) { - buffer.append("classEq("); - buffer.append(in); - buffer.append(")"); - } - - @Override - public boolean matches(Object arg) { - return arg.getClass() == in; - } - - }); - return null; - } - -} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/Base64UrlSafeTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/Base64UrlSafeTest.java deleted file mode 100644 index f6d938a868..0000000000 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/Base64UrlSafeTest.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.internal; - -import static com.google.common.base.Charsets.UTF_8; -import static com.google.common.io.BaseEncoding.base64Url; -import static org.testng.Assert.assertTrue; - -import org.testng.annotations.Test; - -/** - * Tests that the Base64 implementations used to Base64 encode the tokens are Url safe. - */ -@Test(groups = "unit") -public class Base64UrlSafeTest { - - public static final String STRING_THAT_GENERATES_URL_UNSAFE_BASE64_ENCODING = "§1234567890'+±!\"#$%&/()" - + "=?*qwertyuiopº´WERTYUIOPªàsdfghjklç~ASDFGHJKLÇ^ZXCVBNM;:_@€"; - - public void testUsedBase64IsUrlSafe() { - String encoded = base64Url().omitPadding().encode(STRING_THAT_GENERATES_URL_UNSAFE_BASE64_ENCODING.getBytes(UTF_8)); - assertTrue(!encoded.contains("+")); - assertTrue(!encoded.contains("/")); - assertTrue(!encoded.endsWith("=")); - } -} diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java deleted file mode 100644 index 2421d1660d..0000000000 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthApiLiveTest.java +++ /dev/null @@ -1,63 +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 static com.google.common.base.Preconditions.checkNotNull; -import static org.jclouds.oauth.v2.OAuthTestUtils.setCredential; -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.config.OAuthScopes.SingleScope; - -import java.util.Properties; - -import org.jclouds.apis.BaseApiLiveTest; -import org.jclouds.oauth.v2.OAuthApi; -import org.jclouds.oauth.v2.config.OAuthScopes; -import org.testng.annotations.Test; - -import com.google.common.collect.ImmutableList; -import com.google.inject.Binder; -import com.google.inject.Module; - -@Test(groups = "live") -public class BaseOAuthApiLiveTest extends BaseApiLiveTest { - - protected String scope; - - public BaseOAuthApiLiveTest() { - provider = "oauth"; - } - - @Override protected Properties setupProperties() { - Properties props = super.setupProperties(); - setCredential(props, "oauth.credential"); - checkNotNull(setIfTestSystemPropertyPresent(props, "oauth.endpoint"), "test.oauth.endpoint must be set"); - checkNotNull(setIfTestSystemPropertyPresent(props, AUDIENCE), "test.jclouds.oauth.audience must be set"); - scope = setIfTestSystemPropertyPresent(props, "jclouds.oauth.scope"); - setIfTestSystemPropertyPresent(props, JWS_ALG); - return props; - } - - @Override protected Iterable setupModules() { - return ImmutableList.builder().add(new Module() { - @Override public void configure(Binder binder) { - binder.bind(OAuthScopes.class).toInstance(SingleScope.create(scope)); - } - }).addAll(super.setupModules()).build(); - } -} - diff --git a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java b/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java deleted file mode 100644 index 558d313249..0000000000 --- a/apis/oauth/src/test/java/org/jclouds/oauth/v2/internal/BaseOAuthAuthenticatedApiLiveTest.java +++ /dev/null @@ -1,112 +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 static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; -import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static java.util.concurrent.TimeUnit.SECONDS; -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 static org.testng.Assert.assertNotNull; - -import java.io.Closeable; -import java.util.Map; -import java.util.Properties; - -import org.jclouds.apis.BaseApiLiveTest; -import org.jclouds.config.ValueOfConfigurationKeyOrNull; -import org.jclouds.oauth.v2.JWSAlgorithms; -import org.jclouds.oauth.v2.OAuthApi; -import org.jclouds.oauth.v2.domain.Header; -import org.jclouds.oauth.v2.domain.Token; -import org.jclouds.oauth.v2.domain.TokenRequest; -import org.testng.annotations.Test; - -import com.google.common.base.Function; -import com.google.common.collect.ImmutableMap; -import com.google.common.reflect.TypeToken; -import com.google.inject.Injector; -import com.google.inject.Key; -import com.google.inject.Module; - -/** - * A base test of oauth authenticated rest providers. Providers must set the following properties: - *

    - * - oauth.endpoint - * - oauth.audience - * - oauth.jws-alg - *

    - * - oauth.scopes is provided by the subclass - *

    - * This test asserts that a provider can authenticate with oauth for a given scope, or more simply - * that authentication/authorization is working. - */ - -@Test(groups = "live") -public abstract class BaseOAuthAuthenticatedApiLiveTest extends BaseApiLiveTest { - - protected abstract String getScopes(); - - private OAuthApi oauthApi; - - public void testAuthenticate() { - // obtain the necessary properties from the context - String jwsAlg = checkNotNull(propFunction.apply(JWS_ALG), JWS_ALG); - - checkState(JWSAlgorithms.supportedAlgs().contains(jwsAlg), "Algorithm not supported: %s", jwsAlg); - - String audience = checkNotNull(propFunction.apply(AUDIENCE), AUDIENCE); - - // obtain the scopes from the subclass - String scopes = getScopes(); - - Header header = Header.create(jwsAlg, "JWT"); - - long now = SECONDS.convert(System.currentTimeMillis(), MILLISECONDS); - - Map claims = ImmutableMap.builder() - .put("iss", identity) - .put("scope", scopes) - .put("aud", audience) - .put(EXPIRATION_TIME, now + 3600) - .put(ISSUED_AT, now).build(); - - TokenRequest tokenRequest = TokenRequest.create(header, claims); - - Token token = oauthApi.authenticate(tokenRequest); - - assertNotNull(token, "no token when authenticating " + tokenRequest); - } - - @SuppressWarnings({ "unchecked", "serial" }) - protected A create(Properties props, Iterable modules) { - Injector injector = newBuilder().modules(modules).overrides(props).buildInjector(); - propFunction = injector.getInstance(ValueOfConfigurationKeyOrNull.class); - try { - oauthApi = injector.getInstance(OAuthApi.class); - } catch (Exception e) { - throw new IllegalStateException("Provider has no OAuthApi bound. Was the OAuthAuthenticationModule added?"); - } - return (A) injector.getInstance(Key.get(new TypeToken(getClass()) { - }.getType())); - } - - private Function propFunction; -} diff --git a/apis/oauth/src/test/resources/tokenResponse.json b/apis/oauth/src/test/resources/tokenResponse.json deleted file mode 100644 index 6717a550e9..0000000000 --- a/apis/oauth/src/test/resources/tokenResponse.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "access_token" : "1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M", - "token_type" : "Bearer", - "expires_in" : 3600 -} \ No newline at end of file From 225c45fd4ffec020be7907f23522dba87f99483b Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Tue, 24 Mar 2015 11:06:18 +0100 Subject: [PATCH 32/33] Apache jclouds 1.9.0 release --- apis/oauth/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apis/oauth/pom.xml b/apis/oauth/pom.xml index f978213481..cee42282e1 100644 --- a/apis/oauth/pom.xml +++ b/apis/oauth/pom.xml @@ -22,7 +22,7 @@ org.apache.jclouds.labs jclouds-labs-google - 2.0.0-SNAPSHOT + 1.9.0 From 2a12587bf21b042c71fab51a08e5b380a1639677 Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Tue, 24 Mar 2015 11:07:27 +0100 Subject: [PATCH 33/33] Next development version 2.0.0-SNAPSHOT --- apis/oauth/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apis/oauth/pom.xml b/apis/oauth/pom.xml index cee42282e1..f978213481 100644 --- a/apis/oauth/pom.xml +++ b/apis/oauth/pom.xml @@ -22,7 +22,7 @@ org.apache.jclouds.labs jclouds-labs-google - 1.9.0 + 2.0.0-SNAPSHOT