http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java new file mode 100644 index 0000000..9394cad --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java @@ -0,0 +1,51 @@ +/* + * 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; + +/** + * Configurable properties for jclouds OAuth + */ +public class OAuthProperties { + + /** + * The selected signature algorithm to use to sign the requests. + * <p/> + * 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 <a href="http://tools.ietf.org/html/draft-jones-json-web-token-04">doc</a> + */ + 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. + * + * @see org.jclouds.oauth.v2.config.CredentialType + */ + public static final String CREDENTIAL_TYPE = "jclouds.oauth.credential-type"; + +}
http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java new file mode 100644 index 0000000..57ffd29 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/config/OAuthScopes.java @@ -0,0 +1,40 @@ +/* + * 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 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. + * <p/> + * Sets the scopes for the token request for that particular method. + */ +@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(); + +} http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java new file mode 100644 index 0000000..5c0b348 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/ClaimSet.java @@ -0,0 +1,191 @@ +/* + * 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 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. + * + * @see <a + * href="https://developers.google.com/accounts/docs/OAuth2ServiceAccount" + * >doc</a> + */ +public class ClaimSet extends ForwardingMap<String, String> { + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromClaimSet(this); + } + + public static class Builder { + + private Set<String> requiredClaims; + private ImmutableMap.Builder<String, String> claims = new ImmutableMap.Builder<String, String>(); + private long emissionTime; + private long expirationTime; + + public Builder() { + this(ImmutableSet.<String>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<String> 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<String, String> claims) { + this.claims.putAll(checkNotNull(claims)); + return this; + } + + public ClaimSet build() { + Map<String, String> 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<String, String> claims; + private final long emissionTime; + private final long expirationTime; + + private ClaimSet(Map<String, String> 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<String, String> 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); + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/Header.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/Header.java b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/Header.java new file mode 100644 index 0000000..c230e1d --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/Header.java @@ -0,0 +1,128 @@ +/* + * 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 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 + * + * @see <a href="https://developers.google.com/accounts/docs/OAuth2ServiceAccount">doc</a> + */ +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); + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java new file mode 100644 index 0000000..78cb402 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/OAuthCredentials.java @@ -0,0 +1,129 @@ +/* + * 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<OAuthCredentials> { + + 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()); + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/Token.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/Token.java b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/Token.java new file mode 100644 index 0000000..a18a7eb --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/Token.java @@ -0,0 +1,149 @@ +/* + * 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 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. + */ +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); + } + +} http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/TokenRequest.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/TokenRequest.java b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/TokenRequest.java new file mode 100644 index 0000000..7d1a6a4 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/TokenRequest.java @@ -0,0 +1,131 @@ +/* + * 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 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. + */ +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); + } + + +} http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/TokenRequestFormat.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/TokenRequestFormat.java b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/TokenRequestFormat.java new file mode 100644 index 0000000..f4b80c1 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/domain/TokenRequestFormat.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.oauth.v2.domain; + +import com.google.inject.ImplementedBy; +import org.jclouds.http.HttpRequest; +import org.jclouds.oauth.v2.json.JWTTokenRequestFormat; + +import java.util.Set; + +/** + * Transforms a TokenRequest into a specific format (e.g. JWT token) + */ +@ImplementedBy(JWTTokenRequestFormat.class) +public interface TokenRequestFormat { + + /** + * Transforms the provided HttpRequest into a particular token request with a specific format. + */ + <R extends HttpRequest> R formatRequest(R httpRequest, TokenRequest tokenRequest); + + /** + * The name of the type of the token request, e.g., "JWT" + */ + String getTypeName(); + + /** + * The claims that must be present in the token request for it to be valid. + */ + Set<String> requiredClaims(); +} http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenAuthenticator.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenAuthenticator.java b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenAuthenticator.java new file mode 100644 index 0000000..779ba44 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/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<OAuthCredentials> creds; + + @Inject + BearerTokenAuthenticator(final Supplier<OAuthCredentials> creds) { + this.creds = creds; + } + + @Override + public HttpRequest filter(HttpRequest request) throws HttpException { + return request.toBuilder().addHeader("Authorization", String.format("%s %s", + "Bearer ", creds.get().credential)).build(); + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticationFilter.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticationFilter.java b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticationFilter.java new file mode 100644 index 0000000..e6e5714 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/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 { + +} http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java new file mode 100644 index 0000000..c5c7b6f --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java @@ -0,0 +1,62 @@ +/* + * 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.Function; +import com.google.common.cache.LoadingCache; +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; + +/** + * To be used by client applications to embed an OAuth authentication in their REST requests. + * <p/> + * TODO when we're able to use the OAuthAuthentication an this should be used automatically + */ +@Singleton +public class OAuthAuthenticator implements OAuthAuthenticationFilter { + + private Function<GeneratedHttpRequest, TokenRequest> tokenRequestBuilder; + private Function<TokenRequest, Token> tokenFetcher; + + @Inject + OAuthAuthenticator(Function<GeneratedHttpRequest, TokenRequest> tokenRequestBuilder, LoadingCache<TokenRequest, + Token> tokenFetcher) { + this.tokenRequestBuilder = tokenRequestBuilder; + this.tokenFetcher = tokenFetcher; + } + + @Override + public HttpRequest filter(HttpRequest request) throws HttpException { + 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(); + + } + + +} http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java new file mode 100644 index 0000000..7b869dc --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java @@ -0,0 +1,135 @@ +/* + * 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.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 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.ImmutableMap; +import com.google.common.reflect.Invokable; +import com.google.inject.Inject; +import com.google.inject.name.Named; + +/** + * The default authenticator. + * <p/> + * Builds the default token request with the following claims: iss,scope,aud,iat,exp. + * <p/> + * TODO scopes etc should come from the REST method and not from a global property + */ +@Singleton +public class BuildTokenRequest implements Function<GeneratedHttpRequest, TokenRequest> { + + private final String assertionTargetDescription; + private final String signatureAlgorithm; + private final TokenRequestFormat tokenRequestFormat; + private final Supplier<OAuthCredentials> credentialsSupplier; + private final long tokenDuration; + + @Inject(optional = true) + @Named(ADDITIONAL_CLAIMS) + protected Map<String, String> additionalClaims = ImmutableMap.of(); + + @Inject(optional = true) + @Named(SCOPES) + protected String globalScopes = null; + + // injectable so expect tests can override with a predictable value + @Inject(optional = true) + protected Supplier<Long> timeSourceMillisSinceEpoch = new Supplier<Long>() { + @Override + public Long get() { + return System.currentTimeMillis(); + } + }; + + @Inject + public BuildTokenRequest(@Named(AUDIENCE) String assertionTargetDescription, + @Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureAlgorithm, + TokenRequestFormat tokenRequestFormat, Supplier<OAuthCredentials> credentialsSupplier, + @Named(Constants.PROPERTY_SESSION_INTERVAL) long tokenDuration) { + this.assertionTargetDescription = assertionTargetDescription; + this.signatureAlgorithm = signatureAlgorithm; + this.tokenRequestFormat = tokenRequestFormat; + this.credentialsSupplier = credentialsSupplier; + this.tokenDuration = tokenDuration; + } + + @Override + public TokenRequest apply(GeneratedHttpRequest request) { + long now = timeSourceMillisSinceEpoch.get() / 1000; + + // 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()); + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java new file mode 100644 index 0000000..593c885 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.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.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; + +@Singleton +public class FetchToken implements Function<TokenRequest, Token> { + + private OAuthApi oAuthApi; + + @Inject + public FetchToken(OAuthApi oAuthApi) { + this.oAuthApi = oAuthApi; + } + + @Override + public Token apply(TokenRequest input) { + return this.oAuthApi.authenticate(input); + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java new file mode 100644 index 0000000..45620c0 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/functions/OAuthCredentialsSupplier.java @@ -0,0 +1,125 @@ +/* + * 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.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; +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; + +/** + * Loads {@link OAuthCredentials} from a pem private key using the KeyFactory obtained from the JWT Algorithm + * Name<->KeyFactory name mapping in OAuthConstants. The pem pk algorithm must match the KeyFactory algorithm. + * + * @see org.jclouds.oauth.v2.OAuthConstants#OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES + */ +@Singleton +public class OAuthCredentialsSupplier implements Supplier<OAuthCredentials> { + + private final Supplier<Credentials> creds; + private final LoadingCache<Credentials, OAuthCredentials> keyCache; + + @Inject + public OAuthCredentialsSupplier(@Provider Supplier<Credentials> creds, OAuthCredentialsForCredentials loader, + @Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureOrMacAlgorithm) { + this.creds = creds; + checkArgument(OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES.containsKey(signatureOrMacAlgorithm), + 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<Credentials, OAuthCredentials> { + 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(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) { + Throwable authorizationException = getFirstThrowableOfType(e, AuthorizationException.class); + if (authorizationException != null) { + throw (AuthorizationException) authorizationException; + } + throw propagate(e); + } + } + +} http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java new file mode 100644 index 0000000..471812a --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java @@ -0,0 +1,119 @@ +/* + * 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.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} + */ +public class SignOrProduceMacForToken implements Function<byte[], byte[]> { + + private final Supplier<OAuthCredentials> credentials; + private final String signatureOrMacAlgorithm; + private Function<byte[], byte[]> signatureOrMacFunction; + + + @Inject + public SignOrProduceMacForToken(@Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureOrMacAlgorithm, + Supplier<OAuthCredentials> 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<byte[], byte[]>() { + @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<byte[], byte[]> { + + 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<byte[], byte[]> { + + 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); + } + } + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java new file mode 100644 index 0000000..78d7844 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java @@ -0,0 +1,64 @@ +/* + * 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.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. + */ +@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); + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/handlers/OAuthTokenBinder.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/handlers/OAuthTokenBinder.java b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/handlers/OAuthTokenBinder.java new file mode 100644 index 0000000..1030804 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/handlers/OAuthTokenBinder.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.oauth.v2.handlers; + +import org.jclouds.http.HttpRequest; +import org.jclouds.oauth.v2.domain.TokenRequest; +import org.jclouds.oauth.v2.domain.TokenRequestFormat; +import org.jclouds.rest.Binder; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Generic implementation of a token binder. Uses a provided {@link TokenRequestFormat} to actually bind tokens to + * requests. + */ +@Singleton +public class OAuthTokenBinder implements Binder { + + private final TokenRequestFormat tokenRequestFormat; + + @Inject + OAuthTokenBinder(TokenRequestFormat tokenRequestFormat) { + this.tokenRequestFormat = tokenRequestFormat; + } + + @Override + public <R extends HttpRequest> R bindToRequest(R request, Object input) { + return tokenRequestFormat.formatRequest(request, (TokenRequest) input); + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java new file mode 100644 index 0000000..62b3a26 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/json/ClaimSetTypeAdapter.java @@ -0,0 +1,59 @@ +/* + * 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<ClaimSet> { + + @Override + public void write(JsonWriter out, ClaimSet value) throws IOException { + out.beginObject(); + for (Map.Entry<String, String> 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(); + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/json/HeaderTypeAdapter.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/json/HeaderTypeAdapter.java b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/json/HeaderTypeAdapter.java new file mode 100644 index 0000000..f911a54 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/json/HeaderTypeAdapter.java @@ -0,0 +1,52 @@ +/* + * 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<Header> { + + @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(); + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java new file mode 100644 index 0000000..265cb26 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/java/org/jclouds/oauth/v2/json/JWTTokenRequestFormat.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.oauth.v2.json; + +import static com.google.common.base.Charsets.UTF_8; +import static com.google.common.base.Joiner.on; +import static com.google.common.io.BaseEncoding.base64Url; +import static org.jclouds.io.Payloads.newUrlEncodedFormPayload; + +import java.util.Set; + +import javax.inject.Inject; +import 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 + * <p/> + */ +@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<byte[], byte[]> signer; + private final Json json; + + @Inject + public JWTTokenRequestFormat(Function<byte[], byte[]> signer, Json json) { + this.signer = signer; + this.json = json; + } + + @SuppressWarnings("unchecked") + @Override + public <R extends HttpRequest> 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.<String, String> builder() + .put(GRANT_TYPE_FORM_PARAM, GRANT_TYPE_JWT_BEARER) + .put(ASSERTION_FORM_PARAM, assertion).build()); + + return (R) request.toBuilder().payload(payload).build(); + } + + @Override + public String getTypeName() { + return "JWT"; + } + + @Override + public Set<String> requiredClaims() { + // exp and ist (expiration and emission times) are assumed mandatory already + return ImmutableSet.of("iss", "scope", "aud"); + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata new file mode 100644 index 0000000..ab2c67d --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata @@ -0,0 +1,19 @@ +# +# 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.googlecomputeengine.GoogleComputeEngineApiMetadata +org.jclouds.oauth.v2.OAuthApiMetadata http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/test/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadataTest.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/test/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadataTest.java b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/test/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadataTest.java new file mode 100644 index 0000000..5cb8a99 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/test/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApiMetadataTest.java @@ -0,0 +1,38 @@ +/* + * 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.googlecomputeengine; + +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 GoogleComputeApiMetadata is properly registered in ServiceLoader + * <p/> + * <pre> + * META-INF/services/org.jclouds.apis.ApiMetadata + * </pre> + */ +@Test(groups = "unit", testName = "GoogleComputeApiMetadataTest") +public class GoogleComputeEngineApiMetadataTest extends BaseApiMetadataTest { + public GoogleComputeEngineApiMetadataTest() { + super(new GoogleComputeEngineApiMetadata(), ImmutableSet.<TypeToken<? extends View>>of()); + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/test/java/org/jclouds/googlecomputeengine/GoogleComputeEngineAuthenticatedRestContextLiveTest.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/test/java/org/jclouds/googlecomputeengine/GoogleComputeEngineAuthenticatedRestContextLiveTest.java b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/test/java/org/jclouds/googlecomputeengine/GoogleComputeEngineAuthenticatedRestContextLiveTest.java new file mode 100644 index 0000000..8961bb5 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/test/java/org/jclouds/googlecomputeengine/GoogleComputeEngineAuthenticatedRestContextLiveTest.java @@ -0,0 +1,33 @@ +/* + * 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.googlecomputeengine; + +import org.jclouds.oauth.v2.internal.BaseOAuthAuthenticatedApiLiveTest; +import org.testng.annotations.Test; + +@Test(groups = "live") +public class GoogleComputeEngineAuthenticatedRestContextLiveTest extends BaseOAuthAuthenticatedApiLiveTest<GoogleComputeEngineApi> { + + public GoogleComputeEngineAuthenticatedRestContextLiveTest() { + provider = "google-compute-engine"; + } + + @Override + public String getScopes() { + return GoogleComputeEngineConstants.COMPUTE_SCOPE; + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/b45ae00e/dependencies/jclouds/apis/gce/1.8.1-stratos/src/test/java/org/jclouds/googlecomputeengine/PageSystemExpectTest.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/gce/1.8.1-stratos/src/test/java/org/jclouds/googlecomputeengine/PageSystemExpectTest.java b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/test/java/org/jclouds/googlecomputeengine/PageSystemExpectTest.java new file mode 100644 index 0000000..8fa44b9 --- /dev/null +++ b/dependencies/jclouds/apis/gce/1.8.1-stratos/src/test/java/org/jclouds/googlecomputeengine/PageSystemExpectTest.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.googlecomputeengine; + +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; +import static org.testng.Assert.assertSame; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecomputeengine.domain.Image; +import org.jclouds.googlecomputeengine.features.ImageApi; +import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiExpectTest; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +/** + * A test specifically for the paging system. The code used is common to all list() methods so we're using Images + * but it could be anything else. + */ +@Test(groups = "unit") +public class PageSystemExpectTest extends BaseGoogleComputeEngineApiExpectTest { + + public void testGetSinglePage() { + HttpRequest list = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/images") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/image_list_single_page.json")).build(); + + ImageApi imageApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, list, operationResponse).getImageApiForProject("myproject"); + + PagedIterable<Image> images = imageApi.list(); + + // expect one page + assertSame(images.size(), 1); + // with three images + assertSame(images.concat().size(), 3); + } + + public void testGetMultiplePages() { + HttpRequest list1 = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/images?maxResults=3") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpRequest list2 = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/images?pageToken" + + "=CgVJTUFHRRIbZ29vZ2xlLmNlbnRvcy02LTItdjIwMTIwNjIx&maxResults=3") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpRequest list3 = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1/projects/myproject/global/images?pageToken" + + "=CgVJTUFHRRIbZ29vZ2xlLmdjZWwtMTAtMDQtdjIwMTIxMTA2&maxResults=3") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse list1response = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/image_list_multiple_page_1.json")).build(); + + HttpResponse list2Response = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/image_list_multiple_page_2.json")).build(); + + HttpResponse list3Response = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/image_list_single_page.json")).build(); + + + ImageApi imageApi = orderedRequestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, list1, list1response, list2, list2Response, list3, list3Response) + .getImageApiForProject("myproject"); + + PagedIterable<Image> images = imageApi.list(new ListOptions.Builder().maxResults(3)); + + int imageCounter = 0; + for (IterableWithMarker<Image> page : images) { + for (Image image : page) { + imageCounter++; + } + } + assertSame(imageCounter, 9); + } + +}
