diff --git a/labs/aws-sts/pom.xml b/labs/aws-sts/pom.xml
new file mode 100644
index 0000000000..e20ae8fdd3
--- /dev/null
+++ b/labs/aws-sts/pom.xml
@@ -0,0 +1,108 @@
+
+
+
+ 4.0.0
+
+ org.jclouds
+ jclouds-project
+ 1.6.0-SNAPSHOT
+ ../../project/pom.xml
+
+ org.jclouds.labs
+ aws-sts
+ jclouds Amazon Identity and Access Management (STS) provider
+ Identity and Access Management (STS) to Amazon Web Services
+ bundle
+
+
+ https://sts.amazonaws.com
+ 2011-06-15
+
+ ${test.aws.identity}
+ ${test.aws.credential}
+
+ org.jclouds.aws.sts*;version="${project.version}"
+ org.jclouds*;version="${project.version}",*
+
+
+
+
+ org.jclouds.labs
+ sts
+ ${project.version}
+ jar
+
+
+ org.jclouds.labs
+ sts
+ ${project.version}
+ test-jar
+ test
+
+
+ org.jclouds
+ jclouds-core
+ ${project.version}
+ test-jar
+ test
+
+
+ org.jclouds.driver
+ jclouds-log4j
+ ${project.version}
+ test
+
+
+
+
+
+ live
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ integration
+ integration-test
+
+ test
+
+
+
+ ${test.aws-sts.endpoint}
+ ${test.aws-sts.api-version}
+ ${test.aws-sts.build-version}
+ ${test.aws-sts.identity}
+ ${test.aws-sts.credential}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/labs/aws-sts/src/main/java/org/jclouds/aws/sts/AWSSTSProviderMetadata.java b/labs/aws-sts/src/main/java/org/jclouds/aws/sts/AWSSTSProviderMetadata.java
new file mode 100644
index 0000000000..7a6584ba2d
--- /dev/null
+++ b/labs/aws-sts/src/main/java/org/jclouds/aws/sts/AWSSTSProviderMetadata.java
@@ -0,0 +1,84 @@
+/**
+ * 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.aws.sts;
+
+import java.net.URI;
+import java.util.Properties;
+
+import org.jclouds.sts.STSApiMetadata;
+import org.jclouds.providers.ProviderMetadata;
+import org.jclouds.providers.internal.BaseProviderMetadata;
+
+/**
+ * Implementation of @ link org.jclouds.types.ProviderMetadata} for Amazon's STS
+ * provider.
+*
+* @author Adrian Cole
+*/
+public class AWSSTSProviderMetadata extends BaseProviderMetadata {
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ @Override
+ public Builder toBuilder() {
+ return builder().fromProviderMetadata(this);
+ }
+
+ public AWSSTSProviderMetadata() {
+ super(builder());
+ }
+
+ public AWSSTSProviderMetadata(Builder builder) {
+ super(builder);
+ }
+
+ public static Properties defaultProperties() {
+ Properties properties = new Properties();
+ return properties;
+ }
+
+ public static class Builder extends BaseProviderMetadata.Builder {
+
+ protected Builder(){
+ id("aws-sts")
+ .name("Amazon STS")
+ .endpoint("https://sts.amazonaws.com")
+ .homepage(URI.create("http://aws.amazon.com/iam/"))
+ .console(URI.create("https://console.aws.amazon.com/iam/home"))
+ .linkedServices("aws-ec2", "aws-elb", "aws-iam", "aws-sts", "aws-cloudwatch", "aws-s3", "aws-sqs", "aws-simpledb")
+ .iso3166Codes("US-VA")
+ .apiMetadata(new STSApiMetadata())
+ .defaultProperties(AWSSTSProviderMetadata.defaultProperties());
+ }
+
+ @Override
+ public AWSSTSProviderMetadata build() {
+ return new AWSSTSProviderMetadata(this);
+ }
+
+ @Override
+ public Builder fromProviderMetadata(ProviderMetadata in) {
+ super.fromProviderMetadata(in);
+ return this;
+ }
+
+ }
+}
diff --git a/labs/aws-sts/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata b/labs/aws-sts/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
new file mode 100644
index 0000000000..3c3406f91e
--- /dev/null
+++ b/labs/aws-sts/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
@@ -0,0 +1 @@
+org.jclouds.aws.sts.AWSSTSProviderMetadata
diff --git a/labs/aws-sts/src/test/java/org/jclouds/aws/sts/AWSSTSApiLiveTest.java b/labs/aws-sts/src/test/java/org/jclouds/aws/sts/AWSSTSApiLiveTest.java
new file mode 100644
index 0000000000..fee174a6fc
--- /dev/null
+++ b/labs/aws-sts/src/test/java/org/jclouds/aws/sts/AWSSTSApiLiveTest.java
@@ -0,0 +1,35 @@
+/**
+ * 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.aws.sts;
+
+import org.jclouds.sts.STSApiLiveTest;
+import org.testng.annotations.Test;
+
+/**
+ * Tests behavior of {@code STSApi}
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = "live", singleThreaded = true, testName = "AWSSTSApiLiveTest")
+public class AWSSTSApiLiveTest extends STSApiLiveTest {
+ public AWSSTSApiLiveTest() {
+ provider = "aws-sts";
+ }
+
+}
diff --git a/labs/aws-sts/src/test/java/org/jclouds/aws/sts/AWSSTSProviderTest.java b/labs/aws-sts/src/test/java/org/jclouds/aws/sts/AWSSTSProviderTest.java
new file mode 100644
index 0000000000..d6d021cd72
--- /dev/null
+++ b/labs/aws-sts/src/test/java/org/jclouds/aws/sts/AWSSTSProviderTest.java
@@ -0,0 +1,37 @@
+/**
+ * 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.aws.sts;
+
+import org.jclouds.aws.sts.AWSSTSProviderMetadata;
+import org.jclouds.sts.STSApiMetadata;
+import org.jclouds.providers.internal.BaseProviderMetadataTest;
+import org.testng.annotations.Test;
+
+/**
+ * The AWSSTSProviderTest tests the org.jclouds.providers.AWSSTSProvider class.
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "AWSSTSProviderTest")
+public class AWSSTSProviderTest extends BaseProviderMetadataTest {
+
+ public AWSSTSProviderTest() {
+ super(new AWSSTSProviderMetadata(), new STSApiMetadata());
+ }
+}
diff --git a/labs/pom.xml b/labs/pom.xml
index bcb3046938..2e8fbbf1c2 100644
--- a/labs/pom.xml
+++ b/labs/pom.xml
@@ -63,5 +63,7 @@
oauth
openstack-quantum
openstack-glance
+ sts
+ aws-sts
diff --git a/labs/sts/pom.xml b/labs/sts/pom.xml
new file mode 100644
index 0000000000..08f965ac30
--- /dev/null
+++ b/labs/sts/pom.xml
@@ -0,0 +1,107 @@
+
+
+
+ 4.0.0
+
+ org.jclouds
+ jclouds-project
+ 1.6.0-SNAPSHOT
+ ../../project/pom.xml
+
+ org.jclouds.labs
+ sts
+ jcloud sts api
+ jclouds components to access an implementation of Security Token Service (STS)
+ bundle
+
+
+ https://sts.amazonaws.com
+ 2011-06-15
+
+ ${test.aws.identity}
+ ${test.aws.credential}
+
+ org.jclouds.sts*;version="${project.version}"
+ org.jclouds*;version="${project.version}",*
+
+
+
+
+ org.jclouds.common
+ aws-common
+ ${project.version}
+ jar
+
+
+ org.jclouds
+ jclouds-core
+ ${project.version}
+ test-jar
+ test
+
+
+ org.jclouds.driver
+ jclouds-log4j
+ ${project.version}
+ test
+
+
+ log4j
+ log4j
+ test
+
+
+
+
+
+ live
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ integration
+ integration-test
+
+ test
+
+
+
+ ${test.sts.endpoint}
+ ${test.sts.api-version}
+ ${test.sts.build-version}
+ ${test.sts.identity}
+ ${test.sts.credential}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/labs/sts/src/main/java/org/jclouds/sts/STSApi.java b/labs/sts/src/main/java/org/jclouds/sts/STSApi.java
new file mode 100644
index 0000000000..95f084b7bf
--- /dev/null
+++ b/labs/sts/src/main/java/org/jclouds/sts/STSApi.java
@@ -0,0 +1,83 @@
+/**
+ * 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.sts;
+
+import org.jclouds.aws.domain.TemporaryCredentials;
+import org.jclouds.sts.domain.User;
+import org.jclouds.sts.domain.UserAndTemporaryCredentials;
+import org.jclouds.sts.options.AssumeRoleOptions;
+import org.jclouds.sts.options.FederatedUserOptions;
+import org.jclouds.sts.options.TemporaryCredentialsOptions;
+
+/**
+ * Provides access to Amazon STS via the Query API
+ *
+ *
+ * @see STSAsyncApi
+ * @see
+ * @author Adrian Cole
+ */
+public interface STSApi {
+ /**
+ * Returns a set of temporary credentials for an AWS account or IAM user,
+ * with a default timeout
+ */
+ TemporaryCredentials createTemporaryCredentials();
+
+ /**
+ * like {@link #createTemporaryCredentials()}, except you can modify the
+ * timeout and other parameters.
+ */
+ TemporaryCredentials createTemporaryCredentials(TemporaryCredentialsOptions options);
+
+ /**
+ * Assumes a role for a specified session. Only IAM users can assume a role.
+ *
+ * @param sessionName
+ * An identifier for the assumed role session, included as part of
+ * {@link User#getId}.
+ * @param roleArn
+ * The Amazon Resource Name (ARN) of the role that the caller is
+ * assuming.
+ */
+ UserAndTemporaryCredentials assumeRole(String roleArn, String sessionName);
+
+ /**
+ * like {@link #assumeRole(String, String)}, except you can modify the
+ * timeout and other parameters.
+ */
+ UserAndTemporaryCredentials assumeRole(String roleArn, String sessionName, AssumeRoleOptions options);
+
+ /**
+ * Returns a set of temporary credentials for a federated user with the user
+ * name specified.
+ *
+ * @param userName
+ * The name of the federated user, included as part of
+ * {@link User#getId}.
+ */
+ UserAndTemporaryCredentials createFederatedUser(String userName);
+
+ /**
+ * like {@link #createFederatedUser(String)}, except you can modify the
+ * timeout and other parameters.
+ */
+ UserAndTemporaryCredentials createFederatedUser(String userName, FederatedUserOptions options);
+
+}
diff --git a/labs/sts/src/main/java/org/jclouds/sts/STSApiMetadata.java b/labs/sts/src/main/java/org/jclouds/sts/STSApiMetadata.java
new file mode 100644
index 0000000000..4eb7dfb6c0
--- /dev/null
+++ b/labs/sts/src/main/java/org/jclouds/sts/STSApiMetadata.java
@@ -0,0 +1,93 @@
+/**
+ * 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.sts;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
+import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AUTH_TAG;
+import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
+
+import java.net.URI;
+import java.util.Properties;
+
+import org.jclouds.apis.ApiMetadata;
+import org.jclouds.sts.config.STSRestClientModule;
+import org.jclouds.rest.RestContext;
+import org.jclouds.rest.internal.BaseRestApiMetadata;
+
+import com.google.common.reflect.TypeToken;
+
+/**
+ * Implementation of {@link ApiMetadata} for Amazon's STS api.
+ *
+ * @author Adrian Cole
+ */
+public class STSApiMetadata extends BaseRestApiMetadata {
+
+ public static final TypeToken> CONTEXT_TOKEN = new TypeToken>() {
+ private static final long serialVersionUID = 1L;
+ };
+
+ @Override
+ public Builder toBuilder() {
+ return new Builder(getApi(), getAsyncApi()).fromApiMetadata(this);
+ }
+
+ public STSApiMetadata() {
+ this(new Builder(STSApi.class, STSAsyncApi.class));
+ }
+
+ protected STSApiMetadata(Builder builder) {
+ super(Builder.class.cast(builder));
+ }
+
+ public static Properties defaultProperties() {
+ Properties properties = BaseRestApiMetadata.defaultProperties();
+ properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", SECONDS.toMillis(30) + "");
+ properties.setProperty(PROPERTY_AUTH_TAG, "AWS");
+ properties.setProperty(PROPERTY_HEADER_TAG, "amz");
+ return properties;
+ }
+
+ public static class Builder extends BaseRestApiMetadata.Builder {
+
+ protected Builder(Class> api, Class> asyncApi) {
+ super(api, asyncApi);
+ id("sts")
+ .name("Amazon STS Api")
+ .identityName("Access Key ID")
+ .credentialName("Secret Access Key")
+ .version("2011-06-15")
+ .documentation(URI.create("http://docs.amazonwebservices.com/STS/latest/APIReference/"))
+ .defaultEndpoint("https://sts.amazonaws.com")
+ .defaultProperties(STSApiMetadata.defaultProperties())
+ .defaultModule(STSRestClientModule.class);
+ }
+
+ @Override
+ public STSApiMetadata build() {
+ return new STSApiMetadata(this);
+ }
+
+ @Override
+ protected Builder self() {
+ return this;
+ }
+ }
+}
diff --git a/labs/sts/src/main/java/org/jclouds/sts/STSAsyncApi.java b/labs/sts/src/main/java/org/jclouds/sts/STSAsyncApi.java
new file mode 100644
index 0000000000..4a3fdc5482
--- /dev/null
+++ b/labs/sts/src/main/java/org/jclouds/sts/STSAsyncApi.java
@@ -0,0 +1,113 @@
+/**
+ * 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.sts;
+
+import javax.inject.Named;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+
+import org.jclouds.aws.domain.TemporaryCredentials;
+import org.jclouds.aws.filters.FormSigner;
+import org.jclouds.aws.xml.TemporaryCredentialsHandler;
+import org.jclouds.rest.annotations.FormParams;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.VirtualHost;
+import org.jclouds.rest.annotations.XMLResponseParser;
+import org.jclouds.sts.domain.UserAndTemporaryCredentials;
+import org.jclouds.sts.options.AssumeRoleOptions;
+import org.jclouds.sts.options.FederatedUserOptions;
+import org.jclouds.sts.options.TemporaryCredentialsOptions;
+import org.jclouds.sts.xml.UserAndTemporaryCredentialsHandler;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Provides access to Amazon STS via the Query API
+ *
+ *
+ * @see
+ * @author Adrian Cole
+ */
+@RequestFilters(FormSigner.class)
+@VirtualHost
+public interface STSAsyncApi {
+
+ /**
+ * @see STSApi#createTemporaryCredentials()
+ */
+ @Named("GetSessionToken")
+ @POST
+ @Path("/")
+ @XMLResponseParser(TemporaryCredentialsHandler.class)
+ @FormParams(keys = "Action", values = "GetSessionToken")
+ ListenableFuture createTemporaryCredentials();
+
+ /**
+ * @see STSApi#createTemporaryCredentials(TemporaryCredentialsOptions)
+ */
+ @Named("GetSessionToken")
+ @POST
+ @Path("/")
+ @XMLResponseParser(TemporaryCredentialsHandler.class)
+ @FormParams(keys = "Action", values = "GetSessionToken")
+ ListenableFuture createTemporaryCredentials(TemporaryCredentialsOptions options);
+
+ /**
+ * @see STSApi#assumeRole(String, String)
+ */
+ @Named("AssumeRole")
+ @POST
+ @Path("/")
+ @XMLResponseParser(UserAndTemporaryCredentialsHandler.class)
+ @FormParams(keys = "Action", values = "AssumeRole")
+ ListenableFuture assumeRole(@FormParam("RoleArn") String roleArn,
+ @FormParam("RoleSessionName") String sessionName);
+
+ /**
+ * @see STSApi#assumeRole(String, String, AssumeRoleOptions)
+ */
+ @Named("AssumeRole")
+ @POST
+ @Path("/")
+ @XMLResponseParser(UserAndTemporaryCredentialsHandler.class)
+ @FormParams(keys = "Action", values = "AssumeRole")
+ ListenableFuture assumeRole(@FormParam("RoleArn") String roleArn,
+ @FormParam("RoleSessionName") String sessionName, AssumeRoleOptions options);
+
+ /**
+ * @see STSApi#createFederatedUser(String)
+ */
+ @Named("GetFederationToken")
+ @POST
+ @Path("/")
+ @XMLResponseParser(UserAndTemporaryCredentialsHandler.class)
+ @FormParams(keys = "Action", values = "GetFederationToken")
+ ListenableFuture createFederatedUser(@FormParam("Name") String userName);
+
+ /**
+ * @see STSApi#createFederatedUser(FederatedUserOptions)
+ */
+ @Named("GetFederationToken")
+ @POST
+ @Path("/")
+ @XMLResponseParser(UserAndTemporaryCredentialsHandler.class)
+ @FormParams(keys = "Action", values = "GetFederationToken")
+ ListenableFuture createFederatedUser(@FormParam("Name") String userName, FederatedUserOptions options);
+}
diff --git a/labs/sts/src/main/java/org/jclouds/sts/config/STSRestClientModule.java b/labs/sts/src/main/java/org/jclouds/sts/config/STSRestClientModule.java
new file mode 100644
index 0000000000..b912dbd8da
--- /dev/null
+++ b/labs/sts/src/main/java/org/jclouds/sts/config/STSRestClientModule.java
@@ -0,0 +1,40 @@
+/**
+ * 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.sts.config;
+
+import static org.jclouds.reflect.Reflection2.typeToken;
+
+import org.jclouds.aws.config.FormSigningRestClientModule;
+import org.jclouds.rest.ConfiguresRestClient;
+import org.jclouds.sts.STSApi;
+import org.jclouds.sts.STSAsyncApi;
+
+/**
+ * Configures the STS connection.
+ *
+ * @author Adrian Cole
+ */
+@ConfiguresRestClient
+public class STSRestClientModule extends FormSigningRestClientModule {
+
+ public STSRestClientModule() {
+ super(typeToken(STSApi.class), typeToken(STSAsyncApi.class));
+ }
+
+}
diff --git a/labs/sts/src/main/java/org/jclouds/sts/domain/User.java b/labs/sts/src/main/java/org/jclouds/sts/domain/User.java
new file mode 100644
index 0000000000..d97a4a89cc
--- /dev/null
+++ b/labs/sts/src/main/java/org/jclouds/sts/domain/User.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.sts.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Objects;
+
+/**
+ * @author Adrian Cole
+ */
+public final class User {
+ public static User fromIdAndArn(String id, String arn) {
+ return new User(id, arn);
+ }
+
+ private final String id;
+ private final String arn;
+
+ private User(String id, String arn) {
+ this.id = checkNotNull(id, "id");
+ this.arn = checkNotNull(arn, "arn for %s", id);
+ }
+
+ /**
+ * The id of the federated user or assumed role. ex.
+ * {@code ARO123EXAMPLE123:Bob}
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * The arn of the federated user or assumed role.
+ *
+ * ex. {@code arn:aws:sts::123456789012:federated-user/Bob} or
+ * {@code arn:aws:sts::123456789012:assumed-role/demo/Bob}
+ */
+ public String getArn() {
+ return arn;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ User other = (User) obj;
+ return Objects.equal(this.id, other.id) && Objects.equal(this.arn, other.arn);
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this).add("id", id).add("arn", arn).toString();
+ }
+}
diff --git a/labs/sts/src/main/java/org/jclouds/sts/domain/UserAndTemporaryCredentials.java b/labs/sts/src/main/java/org/jclouds/sts/domain/UserAndTemporaryCredentials.java
new file mode 100644
index 0000000000..f2827f178a
--- /dev/null
+++ b/labs/sts/src/main/java/org/jclouds/sts/domain/UserAndTemporaryCredentials.java
@@ -0,0 +1,133 @@
+/**
+ * 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.sts.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.jclouds.aws.domain.TemporaryCredentials;
+
+import com.google.common.base.Objects;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+public final class UserAndTemporaryCredentials {
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public Builder toBuilder() {
+ return builder().from(this);
+ }
+
+ public final static class Builder {
+ private User user;
+ private TemporaryCredentials credentials;
+ private int packedPolicySize;
+
+ /**
+ * @see UserAndTemporaryCredentials#getUser()
+ */
+ public Builder user(User user) {
+ this.user = user;
+ return this;
+ }
+
+ /**
+ * @see UserAndTemporaryCredentials#getCredentials()
+ */
+ public Builder credentials(TemporaryCredentials credentials) {
+ this.credentials = credentials;
+ return this;
+ }
+
+ /**
+ * @see UserAndTemporaryCredentials#getPackedPolicySize()
+ */
+ public Builder packedPolicySize(int packedPolicySize) {
+ this.packedPolicySize = packedPolicySize;
+ return this;
+ }
+
+ public UserAndTemporaryCredentials build() {
+ return new UserAndTemporaryCredentials(user, credentials, packedPolicySize);
+ }
+
+ public Builder from(UserAndTemporaryCredentials in) {
+ return this.user(in.user).credentials(in.credentials).packedPolicySize(in.packedPolicySize);
+ }
+ }
+
+ private final User user;
+ private final TemporaryCredentials credentials;
+ private final int packedPolicySize;
+
+ private UserAndTemporaryCredentials(User user, TemporaryCredentials credentials, int packedPolicySize) {
+ this.user = checkNotNull(user, "user");
+ this.credentials = checkNotNull(credentials, "credentials for %s", user);
+ this.packedPolicySize = checkNotNull(packedPolicySize, "packedPolicySize for %s", user);
+ }
+
+ /**
+ * user correlating to {@link UserAndTemporaryCredentials#getCredentials()}
+ */
+ public User getUser() {
+ return user;
+ }
+
+ /**
+ * The temporary security credentials, which includes an Access Key ID, a
+ * Secret Access Key, and a security token.
+ */
+ public TemporaryCredentials getCredentials() {
+ return credentials;
+ }
+
+ /**
+ * A percentage value that indicates the size of the policy in packed form.
+ */
+ public int getPackedPolicySize() {
+ return packedPolicySize;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(user, credentials, packedPolicySize);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ UserAndTemporaryCredentials other = (UserAndTemporaryCredentials) obj;
+ return Objects.equal(this.user, other.user) && Objects.equal(this.credentials, other.credentials)
+ && Objects.equal(this.packedPolicySize, other.packedPolicySize);
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this).add("user", user).add("credentials", credentials)
+ .add("packedPolicySize", packedPolicySize).toString();
+ }
+}
diff --git a/labs/sts/src/main/java/org/jclouds/sts/options/AssumeRoleOptions.java b/labs/sts/src/main/java/org/jclouds/sts/options/AssumeRoleOptions.java
new file mode 100644
index 0000000000..3a07afedf4
--- /dev/null
+++ b/labs/sts/src/main/java/org/jclouds/sts/options/AssumeRoleOptions.java
@@ -0,0 +1,140 @@
+/**
+ * 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.sts.options;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.Multimap;
+
+/**
+ * @see
+ *
+ * @author Adrian Cole
+ */
+public class AssumeRoleOptions extends BaseHttpRequestOptions implements Cloneable {
+
+ // long as this is a more typical unit for duration, hence less casting
+ private Long durationSeconds;
+ private String policy;
+ private String externalId;
+
+ /**
+ * A unique identifier that is generated by a third party for each of their customers.
+ */
+ public AssumeRoleOptions externalId(String externalId) {
+ this.externalId = externalId;
+ return this;
+ }
+
+ /**
+ * The duration, in seconds, that the credentials should remain valid. 12
+ * hours is default. 15 minutes is current minimum.
+ */
+ public AssumeRoleOptions durationSeconds(long durationSeconds) {
+ this.durationSeconds = durationSeconds;
+ return this;
+ }
+
+ /**
+ * A supplemental policy that can be associated with the temporary security credentials.
+ */
+ public AssumeRoleOptions policy(String policy) {
+ this.policy = policy;
+ return this;
+ }
+
+ public static class Builder {
+
+ /**
+ * @see AssumeRoleOptions#externalId
+ */
+ public static AssumeRoleOptions externalId(String externalId) {
+ return new AssumeRoleOptions().externalId(externalId);
+ }
+
+ /**
+ * @see AssumeRoleOptions#durationSeconds
+ */
+ public static AssumeRoleOptions durationSeconds(long durationSeconds) {
+ return new AssumeRoleOptions().durationSeconds(durationSeconds);
+ }
+
+ /**
+ * @see AssumeRoleOptions#policy
+ */
+ public static AssumeRoleOptions policy(String policy) {
+ return new AssumeRoleOptions().policy(policy);
+ }
+ }
+
+ @Override
+ public Multimap buildFormParameters() {
+ Multimap params = super.buildFormParameters();
+ if (externalId != null)
+ params.put("ExternalId", externalId.toString());
+ if (durationSeconds != null)
+ params.put("DurationSeconds", durationSeconds.toString());
+ if (policy != null)
+ params.put("Policy", policy);
+ return params;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(externalId, durationSeconds, policy);
+ }
+
+ @Override
+ public AssumeRoleOptions clone() {
+ return new AssumeRoleOptions().externalId(externalId).durationSeconds(durationSeconds)
+ .policy(policy);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ AssumeRoleOptions other = AssumeRoleOptions.class.cast(obj);
+ return Objects.equal(this.externalId, other.externalId)
+ && Objects.equal(this.durationSeconds, other.durationSeconds)
+ && Objects.equal(this.policy, other.policy);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this).omitNullValues().add("externalId", externalId)
+ .add("durationSeconds", durationSeconds).add("policy", policy).toString();
+ }
+}
diff --git a/labs/sts/src/main/java/org/jclouds/sts/options/FederatedUserOptions.java b/labs/sts/src/main/java/org/jclouds/sts/options/FederatedUserOptions.java
new file mode 100644
index 0000000000..8d32faa26a
--- /dev/null
+++ b/labs/sts/src/main/java/org/jclouds/sts/options/FederatedUserOptions.java
@@ -0,0 +1,120 @@
+/**
+ * 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.sts.options;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.Multimap;
+
+/**
+ * @see
+ *
+ * @author Adrian Cole
+ */
+public class FederatedUserOptions extends BaseHttpRequestOptions implements Cloneable {
+
+ // long as this is a more typical unit for duration, hence less casting
+ private Long durationSeconds;
+ private String policy;
+
+ /**
+ * The duration, in seconds, that the credentials should remain valid. 12
+ * hours is default. 15 minutes is current minimum.
+ */
+ public FederatedUserOptions durationSeconds(long durationSeconds) {
+ this.durationSeconds = durationSeconds;
+ return this;
+ }
+
+ /**
+ * A supplemental policy that can be associated with the temporary security
+ * credentials.
+ */
+ public FederatedUserOptions policy(String policy) {
+ this.policy = policy;
+ return this;
+ }
+
+ public static class Builder {
+
+ /**
+ * @see FederatedUserOptions#durationSeconds
+ */
+ public static FederatedUserOptions durationSeconds(long durationSeconds) {
+ return new FederatedUserOptions().durationSeconds(durationSeconds);
+ }
+
+ /**
+ * @see FederatedUserOptions#policy
+ */
+ public static FederatedUserOptions policy(String policy) {
+ return new FederatedUserOptions().policy(policy);
+ }
+ }
+
+ @Override
+ public Multimap buildFormParameters() {
+ Multimap params = super.buildFormParameters();
+ if (durationSeconds != null)
+ params.put("DurationSeconds", durationSeconds.toString());
+ if (policy != null)
+ params.put("Policy", policy);
+ return params;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(durationSeconds, policy);
+ }
+
+ @Override
+ public FederatedUserOptions clone() {
+ return new FederatedUserOptions().durationSeconds(durationSeconds).policy(policy);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ FederatedUserOptions other = FederatedUserOptions.class.cast(obj);
+ return Objects.equal(this.durationSeconds, other.durationSeconds) && Objects.equal(this.policy, other.policy);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this).omitNullValues().add("durationSeconds", durationSeconds)
+ .add("policy", policy).toString();
+ }
+}
diff --git a/labs/sts/src/main/java/org/jclouds/sts/options/TemporaryCredentialsOptions.java b/labs/sts/src/main/java/org/jclouds/sts/options/TemporaryCredentialsOptions.java
new file mode 100644
index 0000000000..2e9027598a
--- /dev/null
+++ b/labs/sts/src/main/java/org/jclouds/sts/options/TemporaryCredentialsOptions.java
@@ -0,0 +1,142 @@
+/**
+ * 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.sts.options;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.Multimap;
+
+/**
+ * Options used to get a session token.
+ *
+ * @see
+ *
+ * @author Adrian Cole
+ */
+public class TemporaryCredentialsOptions extends BaseHttpRequestOptions implements Cloneable {
+
+ // long as this is a more typical unit for duration, hence less casting
+ private Long durationSeconds;
+ private String tokenCode;
+ private String serialNumber;
+
+ /**
+ * The identification number of the MFA device for the user.
+ */
+ public TemporaryCredentialsOptions serialNumber(String serialNumber) {
+ this.serialNumber = serialNumber;
+ return this;
+ }
+
+ /**
+ * The duration, in seconds, that the credentials should remain valid. 12
+ * hours is default. 15 minutes is current minimum.
+ */
+ public TemporaryCredentialsOptions durationSeconds(long durationSeconds) {
+ this.durationSeconds = durationSeconds;
+ return this;
+ }
+
+ /**
+ * The value provided by the MFA device.
+ */
+ public TemporaryCredentialsOptions tokenCode(String tokenCode) {
+ this.tokenCode = tokenCode;
+ return this;
+ }
+
+ public static class Builder {
+
+ /**
+ * @see TemporaryCredentialsOptions#serialNumber
+ */
+ public static TemporaryCredentialsOptions serialNumber(String serialNumber) {
+ return new TemporaryCredentialsOptions().serialNumber(serialNumber);
+ }
+
+ /**
+ * @see TemporaryCredentialsOptions#durationSeconds
+ */
+ public static TemporaryCredentialsOptions durationSeconds(long durationSeconds) {
+ return new TemporaryCredentialsOptions().durationSeconds(durationSeconds);
+ }
+
+ /**
+ * @see TemporaryCredentialsOptions#tokenCode
+ */
+ public static TemporaryCredentialsOptions tokenCode(String tokenCode) {
+ return new TemporaryCredentialsOptions().tokenCode(tokenCode);
+ }
+ }
+
+ @Override
+ public Multimap buildFormParameters() {
+ Multimap params = super.buildFormParameters();
+ if (serialNumber != null)
+ params.put("SerialNumber", serialNumber.toString());
+ if (durationSeconds != null)
+ params.put("DurationSeconds", durationSeconds.toString());
+ if (tokenCode != null)
+ params.put("TokenCode", tokenCode);
+ return params;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(serialNumber, durationSeconds, tokenCode);
+ }
+
+ @Override
+ public TemporaryCredentialsOptions clone() {
+ return new TemporaryCredentialsOptions().serialNumber(serialNumber).durationSeconds(durationSeconds)
+ .tokenCode(tokenCode);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ TemporaryCredentialsOptions other = TemporaryCredentialsOptions.class.cast(obj);
+ return Objects.equal(this.serialNumber, other.serialNumber)
+ && Objects.equal(this.durationSeconds, other.durationSeconds)
+ && Objects.equal(this.tokenCode, other.tokenCode);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this).omitNullValues().add("serialNumber", serialNumber)
+ .add("durationSeconds", durationSeconds).add("tokenCode", tokenCode).toString();
+ }
+}
diff --git a/labs/sts/src/main/java/org/jclouds/sts/xml/UserAndTemporaryCredentialsHandler.java b/labs/sts/src/main/java/org/jclouds/sts/xml/UserAndTemporaryCredentialsHandler.java
new file mode 100644
index 0000000000..92fffa0219
--- /dev/null
+++ b/labs/sts/src/main/java/org/jclouds/sts/xml/UserAndTemporaryCredentialsHandler.java
@@ -0,0 +1,107 @@
+/**
+ * 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.sts.xml;
+
+import static org.jclouds.util.SaxUtils.currentOrNull;
+import static org.jclouds.util.SaxUtils.equalsOrSuffix;
+
+import org.jclouds.aws.xml.TemporaryCredentialsHandler;
+import org.jclouds.http.functions.ParseSax;
+import org.jclouds.sts.domain.User;
+import org.jclouds.sts.domain.UserAndTemporaryCredentials;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+import com.google.inject.Inject;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+public class UserAndTemporaryCredentialsHandler extends ParseSax.HandlerForGeneratedRequestWithResult {
+
+ private final TemporaryCredentialsHandler credsHandler;
+
+ private StringBuilder currentText = new StringBuilder();
+ private UserAndTemporaryCredentials.Builder builder = UserAndTemporaryCredentials.builder();
+
+ @Inject
+ public UserAndTemporaryCredentialsHandler(TemporaryCredentialsHandler credsHandler) {
+ this.credsHandler = credsHandler;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public UserAndTemporaryCredentials getResult() {
+ try {
+ return builder.build();
+ } finally {
+ builder = UserAndTemporaryCredentials.builder();
+ }
+ }
+
+ private boolean inCreds;
+
+ private String arn;
+ private String id;
+
+ @Override
+ public void startElement(String url, String name, String qName, Attributes attributes) throws SAXException {
+ if (equalsOrSuffix(qName, "Credentials")) {
+ inCreds = true;
+ }
+ if (inCreds) {
+ credsHandler.startElement(url, name, qName, attributes);
+ }
+ }
+
+ @Override
+ public void endElement(String uri, String name, String qName) {
+ if (inCreds) {
+ if (qName.equals("Credentials")) {
+ inCreds = false;
+ builder.credentials(credsHandler.getResult());
+ } else {
+ credsHandler.endElement(uri, name, qName);
+ }
+ } else if (qName.equals("Arn")) {
+ arn = currentOrNull(currentText);
+ } else if (qName.endsWith("Id")) {// FederatedUserId or AssumedRoleId
+ id = currentOrNull(currentText);
+ } else if (qName.endsWith("User")) {// FederatedUser or AssumedRoleUser
+ builder.user(User.fromIdAndArn(id, arn));
+ id = arn = null;
+ } else if (qName.equals("PackedPolicySize")) {
+ builder.packedPolicySize(Integer.parseInt(currentOrNull(currentText)));
+ }
+ currentText = new StringBuilder();
+ }
+
+ @Override
+ public void characters(char ch[], int start, int length) {
+ if (inCreds) {
+ credsHandler.characters(ch, start, length);
+ } else {
+ currentText.append(ch, start, length);
+ }
+ }
+
+}
diff --git a/labs/sts/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata b/labs/sts/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
new file mode 100644
index 0000000000..df7b5d89f7
--- /dev/null
+++ b/labs/sts/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
@@ -0,0 +1 @@
+org.jclouds.sts.STSApiMetadata
diff --git a/labs/sts/src/test/java/org/jclouds/sts/STSApiExpectTest.java b/labs/sts/src/test/java/org/jclouds/sts/STSApiExpectTest.java
new file mode 100644
index 0000000000..0ce231d4bf
--- /dev/null
+++ b/labs/sts/src/test/java/org/jclouds/sts/STSApiExpectTest.java
@@ -0,0 +1,187 @@
+/**
+ * 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
+ *
+ * Unles 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 expres or implied. See the License for the
+ * specific language governing permisions and limitations
+ * under the License.
+ */
+package org.jclouds.sts;
+
+import static org.jclouds.sts.options.AssumeRoleOptions.Builder.externalId;
+import static org.jclouds.sts.options.FederatedUserOptions.Builder.policy;
+import static org.jclouds.sts.options.TemporaryCredentialsOptions.Builder.serialNumber;
+import static org.testng.Assert.assertEquals;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.sts.internal.BaseSTSApiExpectTest;
+import org.jclouds.sts.parse.AssumeRoleResponseTest;
+import org.jclouds.sts.parse.GetFederationTokenResponseTest;
+import org.jclouds.sts.parse.GetSessionTokenResponseTest;
+import org.testng.annotations.Test;
+
+/**
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "STSApiExpectTest")
+public class STSApiExpectTest extends BaseSTSApiExpectTest {
+
+ HttpRequest createTemporaryCredentials = HttpRequest.builder().method("POST")
+ .endpoint("https://sts.amazonaws.com/")
+ .addHeader("Host", "sts.amazonaws.com")
+ .addFormParam("Action", "GetSessionToken")
+ .addFormParam("Signature", "ntC%2BPKAcmYTJ5Py5tjICG4KX5y00Pl2L0XJrLbSgLEs%3D")
+ .addFormParam("SignatureMethod", "HmacSHA256")
+ .addFormParam("SignatureVersion", "2")
+ .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+ .addFormParam("Version", "2011-06-15")
+ .addFormParam("AWSAccessKeyId", "identity").build();
+
+ HttpResponse createTemporaryCredentialsResponse = HttpResponse.builder().statusCode(200)
+ .payload(payloadFromResourceWithContentType("/session_token.xml", "text/xml")).build();
+
+ public void testCreateTemporaryCredentialsWhenResponseIs2xx() {
+
+ STSApi apiWhenWithOptionsExist = requestSendsResponse(createTemporaryCredentials, createTemporaryCredentialsResponse);
+
+ assertEquals(
+ apiWhenWithOptionsExist.createTemporaryCredentials().toString(),
+ new GetSessionTokenResponseTest().expected().toString());
+ }
+
+ HttpRequest createTemporaryCredentialsWithOptions = HttpRequest.builder().method("POST")
+ .endpoint("https://sts.amazonaws.com/")
+ .addHeader("Host", "sts.amazonaws.com")
+ .addFormParam("Action", "GetSessionToken")
+ .addFormParam("DurationSeconds", "900")
+ .addFormParam("SerialNumber", "YourMFADeviceSerialNumber")
+ .addFormParam("Signature", "e4HEkfKrw7EuLEQhe4/lK1l7ZmaynO3snsIMU/cdarI%3D")
+ .addFormParam("SignatureMethod", "HmacSHA256")
+ .addFormParam("SignatureVersion", "2")
+ .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+ .addFormParam("TokenCode", "1234")
+ .addFormParam("Version", "2011-06-15")
+ .addFormParam("AWSAccessKeyId", "identity").build();
+
+ public void testCreateTemporaryCredentialsWithOptionsWhenResponseIs2xx() {
+
+ STSApi apiWhenWithOptionsExist = requestSendsResponse(createTemporaryCredentialsWithOptions, createTemporaryCredentialsResponse);
+
+ assertEquals(
+ apiWhenWithOptionsExist.createTemporaryCredentials(
+ serialNumber("YourMFADeviceSerialNumber").tokenCode("1234").durationSeconds(TimeUnit.MINUTES.toSeconds(15))).toString(),
+ new GetSessionTokenResponseTest().expected().toString());
+ }
+
+ HttpRequest assumeRole = HttpRequest.builder().method("POST")
+ .endpoint("https://sts.amazonaws.com/")
+ .addHeader("Host", "sts.amazonaws.com")
+ .addFormParam("Action", "AssumeRole")
+ .addFormParam("RoleArn", "arn:aws:iam::123456789012:role/demo")
+ .addFormParam("RoleSessionName", "Bob")
+ .addFormParam("Signature", "0G1%2B6GX4cSU9Tjf2SyQ9oW5ivFri4BQPif/24FoRiWY%3D")
+ .addFormParam("SignatureMethod", "HmacSHA256")
+ .addFormParam("SignatureVersion", "2")
+ .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+ .addFormParam("Version", "2011-06-15")
+ .addFormParam("AWSAccessKeyId", "identity").build();
+
+ HttpResponse assumeRoleResponse = HttpResponse.builder().statusCode(200)
+ .payload(payloadFromResourceWithContentType("/assume_role.xml", "text/xml")).build();
+
+ public void testAssumeRoleWhenResponseIs2xx() {
+
+ STSApi apiWhenWithOptionsExist = requestSendsResponse(assumeRole, assumeRoleResponse);
+
+ assertEquals(apiWhenWithOptionsExist.assumeRole("arn:aws:iam::123456789012:role/demo", "Bob").toString(),
+ new AssumeRoleResponseTest().expected().toString());
+ }
+
+ String policy = "{\"Statement\":[{\"Sid\":\"Stmt1\",\"Effect\":\"Allow\",\"Action\":\"s3:*\",\"Resource\":\"*\"}]}";
+
+ HttpRequest assumeRoleWithOptions = HttpRequest.builder().method("POST")
+ .endpoint("https://sts.amazonaws.com/")
+ .addHeader("Host", "sts.amazonaws.com")
+ .addFormParam("Action", "AssumeRole")
+ .addFormParam("DurationSeconds", "900")
+ .addFormParam("ExternalId", "123ABC")
+ .addFormParam("Policy", policy)
+ .addFormParam("RoleArn", "arn:aws:iam::123456789012:role/demo")
+ .addFormParam("RoleSessionName", "Bob")
+ .addFormParam("Signature", "9qffV6zHRbTX8E9IYbEFeQPWrHEdSbwUfjJpg1SMaBo%3D")
+ .addFormParam("SignatureMethod", "HmacSHA256")
+ .addFormParam("SignatureVersion", "2")
+ .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+ .addFormParam("Version", "2011-06-15")
+ .addFormParam("AWSAccessKeyId", "identity").build();
+
+ public void testAssumeRoleWithOptionsWhenResponseIs2xx() {
+
+ STSApi apiWhenWithOptionsExist = requestSendsResponse(assumeRoleWithOptions, assumeRoleResponse);
+
+ assertEquals(
+ apiWhenWithOptionsExist.assumeRole("arn:aws:iam::123456789012:role/demo", "Bob",
+ externalId("123ABC").policy(policy).durationSeconds(TimeUnit.MINUTES.toSeconds(15))).toString(),
+ new AssumeRoleResponseTest().expected().toString());
+ }
+
+ HttpRequest createFederatedUser = HttpRequest.builder().method("POST")
+ .endpoint("https://sts.amazonaws.com/")
+ .addHeader("Host", "sts.amazonaws.com")
+ .addFormParam("Action", "GetFederationToken")
+ .addFormParam("Name", "Bob")
+ .addFormParam("Signature", "Z7AtGK4X9IAx/zMtLD7baNiyltNl%2BF%2BSHqjIGUidzOc%3D")
+ .addFormParam("SignatureMethod", "HmacSHA256")
+ .addFormParam("SignatureVersion", "2")
+ .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+ .addFormParam("Version", "2011-06-15")
+ .addFormParam("AWSAccessKeyId", "identity").build();
+
+ HttpResponse createFederatedUserResponse = HttpResponse.builder().statusCode(200)
+ .payload(payloadFromResourceWithContentType("/federation_token.xml", "text/xml")).build();
+
+ public void testCreateFederatedUserWhenResponseIs2xx() {
+
+ STSApi apiWhenWithOptionsExist = requestSendsResponse(createFederatedUser, createFederatedUserResponse);
+
+ assertEquals(apiWhenWithOptionsExist.createFederatedUser("Bob").toString(), new GetFederationTokenResponseTest()
+ .expected().toString());
+ }
+
+ HttpRequest createFederatedUserWithOptions = HttpRequest.builder().method("POST")
+ .endpoint("https://sts.amazonaws.com/")
+ .addHeader("Host", "sts.amazonaws.com")
+ .addFormParam("Action", "GetFederationToken")
+ .addFormParam("DurationSeconds", "900")
+ .addFormParam("Name", "Bob")
+ .addFormParam("Policy", policy)
+ .addFormParam("Signature", "%2BWGvCNtmb1UPmQHxXPMvcK6vH/TJ9r/wCuxdz03n/2w%3D")
+ .addFormParam("SignatureMethod", "HmacSHA256")
+ .addFormParam("SignatureVersion", "2")
+ .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+ .addFormParam("Version", "2011-06-15")
+ .addFormParam("AWSAccessKeyId", "identity").build();
+
+ public void testCreateFederatedUserWithOptionsWhenResponseIs2xx() {
+
+ STSApi apiWhenWithOptionsExist = requestSendsResponse(createFederatedUserWithOptions, createFederatedUserResponse);
+
+ assertEquals(
+ apiWhenWithOptionsExist.createFederatedUser("Bob",
+ policy(policy).durationSeconds(TimeUnit.MINUTES.toSeconds(15))).toString(),
+ new GetFederationTokenResponseTest().expected().toString());
+ }
+}
diff --git a/labs/sts/src/test/java/org/jclouds/sts/STSApiLiveTest.java b/labs/sts/src/test/java/org/jclouds/sts/STSApiLiveTest.java
new file mode 100644
index 0000000000..68f8b9a55e
--- /dev/null
+++ b/labs/sts/src/test/java/org/jclouds/sts/STSApiLiveTest.java
@@ -0,0 +1,88 @@
+/**
+ * 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.sts;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.aws.domain.TemporaryCredentials;
+import org.jclouds.sts.domain.UserAndTemporaryCredentials;
+import org.jclouds.sts.internal.BaseSTSApiLiveTest;
+import org.jclouds.sts.options.AssumeRoleOptions;
+import org.jclouds.sts.options.FederatedUserOptions;
+import org.jclouds.sts.options.TemporaryCredentialsOptions;
+import org.testng.SkipException;
+import org.testng.annotations.Test;
+
+/**
+ * @author Adrian Cole
+ */
+@Test(groups = "live", singleThreaded = true, testName = "STSApiLiveTest")
+public class STSApiLiveTest extends BaseSTSApiLiveTest {
+
+ @Test
+ protected void testCreateTemporaryCredentials() {
+ TemporaryCredentials creds = api().createTemporaryCredentials(
+ new TemporaryCredentialsOptions().durationSeconds(MINUTES.toSeconds(15)));
+ checkTemporaryCredentials(creds);
+ // TODO: actually login to some service
+ //
+ // context.close();
+ // ProviderMetadata pm = createProviderMetadata();
+ //
+ // context = (pm != null ? ContextBuilder.newBuilder(pm) : ContextBuilder.newBuilder(createApiMetadata()))
+ // .credentialsSupplier(Supplier. of(creds)).modules(setupModules()).build();
+ }
+
+ @Test
+ protected void testCreateFederatedUser() {
+ UserAndTemporaryCredentials user = api().createFederatedUser("Bob", new FederatedUserOptions().durationSeconds(MINUTES.toSeconds(15)));
+ checkTemporaryCredentials(user.getCredentials());
+ assertTrue(user.getUser().getId().contains("Bob"), user + " id incorrect");
+ assertTrue(user.getUser().getArn().contains("Bob"), user + " arn incorrect");
+ assertTrue(user.getPackedPolicySize() >= 0, user + " policy size negative");
+ }
+
+ @Test
+ protected void testAssumeRole() {
+ String arnToAssume = getTestArn();
+ UserAndTemporaryCredentials role = api().assumeRole(arnToAssume, "session",
+ new AssumeRoleOptions().durationSeconds(MINUTES.toSeconds(15)));
+ checkTemporaryCredentials(role.getCredentials());
+ assertTrue(role.getUser().getId().contains("session"), role + " id incorrect");
+ assertTrue(role.getUser().getArn().contains("session"), role + " arn incorrect");
+ assertTrue(role.getPackedPolicySize() >= 0, role + " policy size negative");
+ }
+
+ protected String getTestArn() {
+ throw new SkipException("TODO: need to query a valid arn to assume");
+ }
+
+ private void checkTemporaryCredentials(TemporaryCredentials creds) {
+ checkNotNull(creds.getAccessKeyId(), "AccessKeyId cannot be null for TemporaryCredentials.");
+ checkNotNull(creds.getSecretAccessKey(), "SecretAccessKey cannot be null for TemporaryCredentials.");
+ checkNotNull(creds.getSessionToken(), "SessionToken cannot be null for TemporaryCredentials.");
+ checkNotNull(creds.getExpiration(), "Expiration cannot be null for TemporaryCredentials.");
+ }
+
+ protected STSApi api() {
+ return context.getApi();
+ }
+}
diff --git a/labs/sts/src/test/java/org/jclouds/sts/STSApiMetadataTest.java b/labs/sts/src/test/java/org/jclouds/sts/STSApiMetadataTest.java
new file mode 100644
index 0000000000..98c5431b44
--- /dev/null
+++ b/labs/sts/src/test/java/org/jclouds/sts/STSApiMetadataTest.java
@@ -0,0 +1,39 @@
+/**
+ * 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.sts;
+
+import org.jclouds.View;
+import org.jclouds.rest.internal.BaseRestApiMetadataTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.reflect.TypeToken;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "STSApiMetadataTest")
+public class STSApiMetadataTest extends BaseRestApiMetadataTest {
+
+ // no tenant abstraction, yet
+ public STSApiMetadataTest() {
+ super(new STSApiMetadata(), ImmutableSet.> of());
+ }
+}
diff --git a/labs/sts/src/test/java/org/jclouds/sts/internal/BaseSTSApiExpectTest.java b/labs/sts/src/test/java/org/jclouds/sts/internal/BaseSTSApiExpectTest.java
new file mode 100644
index 0000000000..829a107dc5
--- /dev/null
+++ b/labs/sts/src/test/java/org/jclouds/sts/internal/BaseSTSApiExpectTest.java
@@ -0,0 +1,29 @@
+/**
+ * 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.sts.internal;
+
+import org.jclouds.sts.STSApi;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+public class BaseSTSApiExpectTest extends BaseSTSExpectTest {
+
+}
diff --git a/labs/sts/src/test/java/org/jclouds/sts/internal/BaseSTSApiLiveTest.java b/labs/sts/src/test/java/org/jclouds/sts/internal/BaseSTSApiLiveTest.java
new file mode 100644
index 0000000000..fb1008556c
--- /dev/null
+++ b/labs/sts/src/test/java/org/jclouds/sts/internal/BaseSTSApiLiveTest.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.sts.internal;
+
+import org.jclouds.apis.BaseContextLiveTest;
+import org.jclouds.sts.STSApiMetadata;
+import org.jclouds.sts.STSAsyncApi;
+import org.jclouds.sts.STSApi;
+import org.jclouds.rest.RestContext;
+import org.testng.annotations.Test;
+
+import com.google.common.reflect.TypeToken;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = "live")
+public class BaseSTSApiLiveTest extends
+ BaseContextLiveTest> {
+
+ public BaseSTSApiLiveTest() {
+ provider = "sts";
+ }
+
+ @Override
+ protected TypeToken> contextType() {
+ return STSApiMetadata.CONTEXT_TOKEN;
+ }
+
+}
diff --git a/labs/sts/src/test/java/org/jclouds/sts/internal/BaseSTSAsyncApiExpectTest.java b/labs/sts/src/test/java/org/jclouds/sts/internal/BaseSTSAsyncApiExpectTest.java
new file mode 100644
index 0000000000..e466fee86c
--- /dev/null
+++ b/labs/sts/src/test/java/org/jclouds/sts/internal/BaseSTSAsyncApiExpectTest.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.sts.internal;
+
+import java.util.Properties;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.sts.STSAsyncApi;
+
+import com.google.common.base.Function;
+import com.google.inject.Module;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+public class BaseSTSAsyncApiExpectTest extends BaseSTSExpectTest {
+ public STSAsyncApi createApi(Function fn, Module module, Properties props) {
+ return createInjector(fn, module, props).getInstance(STSAsyncApi.class);
+ }
+}
diff --git a/labs/sts/src/test/java/org/jclouds/sts/internal/BaseSTSExpectTest.java b/labs/sts/src/test/java/org/jclouds/sts/internal/BaseSTSExpectTest.java
new file mode 100644
index 0000000000..b4004180e1
--- /dev/null
+++ b/labs/sts/src/test/java/org/jclouds/sts/internal/BaseSTSExpectTest.java
@@ -0,0 +1,51 @@
+/**
+ * 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.sts.internal;
+
+import org.jclouds.date.DateService;
+import org.jclouds.sts.config.STSRestClientModule;
+import org.jclouds.rest.ConfiguresRestClient;
+import org.jclouds.rest.internal.BaseRestApiExpectTest;
+
+import com.google.inject.Module;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+public class BaseSTSExpectTest extends BaseRestApiExpectTest {
+
+ public BaseSTSExpectTest() {
+ provider = "sts";
+ }
+
+ @ConfiguresRestClient
+ private static final class TestSTSRestClientModule extends STSRestClientModule {
+
+ @Override
+ protected String provideTimeStamp(final DateService dateService) {
+ return "2009-11-08T15:54:08.897Z";
+ }
+ }
+
+ @Override
+ protected Module createModule() {
+ return new TestSTSRestClientModule();
+ }
+}
diff --git a/labs/sts/src/test/java/org/jclouds/sts/options/AssumeRoleOptionsTest.java b/labs/sts/src/test/java/org/jclouds/sts/options/AssumeRoleOptionsTest.java
new file mode 100644
index 0000000000..bb1faeb4d8
--- /dev/null
+++ b/labs/sts/src/test/java/org/jclouds/sts/options/AssumeRoleOptionsTest.java
@@ -0,0 +1,69 @@
+/**
+ * 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.sts.options;
+
+import static org.jclouds.sts.options.AssumeRoleOptions.Builder.externalId;
+import static org.jclouds.sts.options.AssumeRoleOptions.Builder.durationSeconds;
+import static org.jclouds.sts.options.AssumeRoleOptions.Builder.policy;
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "AssumeRoleOptionsTest")
+public class AssumeRoleOptionsTest {
+
+ public void testExternalId() {
+ AssumeRoleOptions options = new AssumeRoleOptions().externalId("123ABC");
+ assertEquals(ImmutableSet.of("123ABC"), options.buildFormParameters().get("ExternalId"));
+ }
+
+ public void testExternalIdStatic() {
+ AssumeRoleOptions options = externalId("123ABC");
+ assertEquals(ImmutableSet.of("123ABC"), options.buildFormParameters().get("ExternalId"));
+ }
+
+ public void testDurationSeconds() {
+ AssumeRoleOptions options = new AssumeRoleOptions().durationSeconds(3600);
+ assertEquals(ImmutableSet.of("3600"), options.buildFormParameters().get("DurationSeconds"));
+ }
+
+ public void testDurationSecondsStatic() {
+ AssumeRoleOptions options = durationSeconds(3600);
+ assertEquals(ImmutableSet.of("3600"), options.buildFormParameters().get("DurationSeconds"));
+ }
+
+ String policy = "{\"Statement\":[{\"Sid\":\"Stmt1\",\"Effect\":\"Allow\",\"Action\":\"s3:*\",\"Resource\":\"*\"}]}";
+
+ public void testPolicy() {
+ AssumeRoleOptions options = new AssumeRoleOptions().policy(policy);
+ assertEquals(ImmutableSet.of(policy), options.buildFormParameters().get("Policy"));
+ }
+
+ public void testPolicyStatic() {
+ AssumeRoleOptions options = policy(policy);
+ assertEquals(ImmutableSet.of(policy), options.buildFormParameters().get("Policy"));
+ }
+
+}
diff --git a/labs/sts/src/test/java/org/jclouds/sts/options/FederatedUserOptionsTest.java b/labs/sts/src/test/java/org/jclouds/sts/options/FederatedUserOptionsTest.java
new file mode 100644
index 0000000000..b89f64d6e2
--- /dev/null
+++ b/labs/sts/src/test/java/org/jclouds/sts/options/FederatedUserOptionsTest.java
@@ -0,0 +1,58 @@
+/**
+ * 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.sts.options;
+
+import static org.jclouds.sts.options.FederatedUserOptions.Builder.durationSeconds;
+import static org.jclouds.sts.options.FederatedUserOptions.Builder.policy;
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "FederatedUserOptionsTest")
+public class FederatedUserOptionsTest {
+
+ public void testDurationSeconds() {
+ FederatedUserOptions options = new FederatedUserOptions().durationSeconds(3600);
+ assertEquals(ImmutableSet.of("3600"), options.buildFormParameters().get("DurationSeconds"));
+ }
+
+ public void testDurationSecondsStatic() {
+ FederatedUserOptions options = durationSeconds(3600);
+ assertEquals(ImmutableSet.of("3600"), options.buildFormParameters().get("DurationSeconds"));
+ }
+
+ String policy = "{\"Statement\":[{\"Sid\":\"Stmt1\",\"Effect\":\"Allow\",\"Action\":\"s3:*\",\"Resource\":\"*\"}]}";
+
+ public void testPolicy() {
+ FederatedUserOptions options = new FederatedUserOptions().policy(policy);
+ assertEquals(ImmutableSet.of(policy), options.buildFormParameters().get("Policy"));
+ }
+
+ public void testPolicyStatic() {
+ FederatedUserOptions options = policy(policy);
+ assertEquals(ImmutableSet.of(policy), options.buildFormParameters().get("Policy"));
+ }
+
+}
diff --git a/labs/sts/src/test/java/org/jclouds/sts/options/TemporaryCredentialsOptionsTest.java b/labs/sts/src/test/java/org/jclouds/sts/options/TemporaryCredentialsOptionsTest.java
new file mode 100644
index 0000000000..548bce3a59
--- /dev/null
+++ b/labs/sts/src/test/java/org/jclouds/sts/options/TemporaryCredentialsOptionsTest.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.sts.options;
+
+import static org.jclouds.sts.options.TemporaryCredentialsOptions.Builder.serialNumber;
+import static org.jclouds.sts.options.TemporaryCredentialsOptions.Builder.durationSeconds;
+import static org.jclouds.sts.options.TemporaryCredentialsOptions.Builder.tokenCode;
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "TemporaryCredentialsOptionsTest")
+public class TemporaryCredentialsOptionsTest {
+
+ public void testSerialNumber() {
+ TemporaryCredentialsOptions options = new TemporaryCredentialsOptions().serialNumber("YourMFADeviceSerialNumber");
+ assertEquals(ImmutableSet.of("YourMFADeviceSerialNumber"), options.buildFormParameters().get("SerialNumber"));
+ }
+
+ public void testSerialNumberStatic() {
+ TemporaryCredentialsOptions options = serialNumber("YourMFADeviceSerialNumber");
+ assertEquals(ImmutableSet.of("YourMFADeviceSerialNumber"), options.buildFormParameters().get("SerialNumber"));
+ }
+
+ public void testDurationSeconds() {
+ TemporaryCredentialsOptions options = new TemporaryCredentialsOptions().durationSeconds(3600);
+ assertEquals(ImmutableSet.of("3600"), options.buildFormParameters().get("DurationSeconds"));
+ }
+
+ public void testDurationSecondsStatic() {
+ TemporaryCredentialsOptions options = durationSeconds(3600);
+ assertEquals(ImmutableSet.of("3600"), options.buildFormParameters().get("DurationSeconds"));
+ }
+
+ public void testTokenCode() {
+ TemporaryCredentialsOptions options = new TemporaryCredentialsOptions().tokenCode("123456");
+ assertEquals(ImmutableSet.of("123456"), options.buildFormParameters().get("TokenCode"));
+ }
+
+ public void testTokenCodeStatic() {
+ TemporaryCredentialsOptions options = tokenCode("123456");
+ assertEquals(ImmutableSet.of("123456"), options.buildFormParameters().get("TokenCode"));
+ }
+
+}
diff --git a/labs/sts/src/test/java/org/jclouds/sts/parse/AssumeRoleResponseTest.java b/labs/sts/src/test/java/org/jclouds/sts/parse/AssumeRoleResponseTest.java
new file mode 100644
index 0000000000..b8a3e74b5d
--- /dev/null
+++ b/labs/sts/src/test/java/org/jclouds/sts/parse/AssumeRoleResponseTest.java
@@ -0,0 +1,57 @@
+/**
+ * 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.sts.parse;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.InputStream;
+
+import org.jclouds.http.functions.BaseHandlerTest;
+import org.jclouds.sts.domain.UserAndTemporaryCredentials;
+import org.jclouds.sts.domain.User;
+import org.jclouds.sts.xml.UserAndTemporaryCredentialsHandler;
+import org.testng.annotations.Test;
+
+/**
+ * @author Adrian Cole
+ */
+// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
+@Test(groups = "unit", testName = "AssumeRoleResponseTest")
+public class AssumeRoleResponseTest extends BaseHandlerTest {
+
+ public void test() {
+ InputStream is = getClass().getResourceAsStream("/assume_role.xml");
+
+ UserAndTemporaryCredentials expected = expected();
+
+ UserAndTemporaryCredentialsHandler handler = injector.getInstance(UserAndTemporaryCredentialsHandler.class);
+ UserAndTemporaryCredentials result = factory.create(handler).parse(is);
+
+ assertEquals(result, expected);
+ assertEquals(result.getUser(), expected.getUser());
+ assertEquals(result.getPackedPolicySize(), expected.getPackedPolicySize());
+ }
+
+ public UserAndTemporaryCredentials expected() {
+ return UserAndTemporaryCredentials.builder()
+ .credentials(new GetSessionTokenResponseTest().expected())
+ .user(User.fromIdAndArn("ARO123EXAMPLE123:Bob", "arn:aws:sts::123456789012:assumed-role/demo/Bob"))
+ .packedPolicySize(6).build();
+ }
+}
diff --git a/labs/sts/src/test/java/org/jclouds/sts/parse/GetFederationTokenResponseTest.java b/labs/sts/src/test/java/org/jclouds/sts/parse/GetFederationTokenResponseTest.java
new file mode 100644
index 0000000000..0a5e6e3b9d
--- /dev/null
+++ b/labs/sts/src/test/java/org/jclouds/sts/parse/GetFederationTokenResponseTest.java
@@ -0,0 +1,57 @@
+/**
+ * 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.sts.parse;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.InputStream;
+
+import org.jclouds.http.functions.BaseHandlerTest;
+import org.jclouds.sts.domain.UserAndTemporaryCredentials;
+import org.jclouds.sts.domain.User;
+import org.jclouds.sts.xml.UserAndTemporaryCredentialsHandler;
+import org.testng.annotations.Test;
+
+/**
+ * @author Adrian Cole
+ */
+// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
+@Test(groups = "unit", testName = "GetFederationTokenResponseTest")
+public class GetFederationTokenResponseTest extends BaseHandlerTest {
+
+ public void test() {
+ InputStream is = getClass().getResourceAsStream("/federation_token.xml");
+
+ UserAndTemporaryCredentials expected = expected();
+
+ UserAndTemporaryCredentialsHandler handler = injector.getInstance(UserAndTemporaryCredentialsHandler.class);
+ UserAndTemporaryCredentials result = factory.create(handler).parse(is);
+
+ assertEquals(result, expected);
+ assertEquals(result.getUser(), expected.getUser());
+ assertEquals(result.getPackedPolicySize(), expected.getPackedPolicySize());
+ }
+
+ public UserAndTemporaryCredentials expected() {
+ return UserAndTemporaryCredentials.builder()
+ .credentials(new GetSessionTokenResponseTest().expected())
+ .user(User.fromIdAndArn("123456789012:Bob", "arn:aws:sts::123456789012:federated-user/Bob"))
+ .packedPolicySize(6).build();
+ }
+}
diff --git a/labs/sts/src/test/java/org/jclouds/sts/parse/GetSessionTokenResponseTest.java b/labs/sts/src/test/java/org/jclouds/sts/parse/GetSessionTokenResponseTest.java
new file mode 100644
index 0000000000..bd2aeec8c9
--- /dev/null
+++ b/labs/sts/src/test/java/org/jclouds/sts/parse/GetSessionTokenResponseTest.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.sts.parse;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.InputStream;
+
+import org.jclouds.aws.domain.TemporaryCredentials;
+import org.jclouds.aws.xml.TemporaryCredentialsHandler;
+import org.jclouds.date.internal.SimpleDateFormatDateService;
+import org.jclouds.http.functions.BaseHandlerTest;
+import org.testng.annotations.Test;
+
+/**
+ * @author Adrian Cole
+ */
+// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
+@Test(groups = "unit", testName = "GetSessionTokenResponseTest")
+public class GetSessionTokenResponseTest extends BaseHandlerTest {
+
+ public void test() {
+ InputStream is = getClass().getResourceAsStream("/session_token.xml");
+
+ TemporaryCredentials expected = expected();
+
+ TemporaryCredentialsHandler handler = injector.getInstance(TemporaryCredentialsHandler.class);
+ TemporaryCredentials result = factory.create(handler).parse(is);
+
+ assertEquals(result, expected);
+ assertEquals(result.getAccessKeyId(), expected.getAccessKeyId());
+ assertEquals(result.getSecretAccessKey(), expected.getSecretAccessKey());
+ assertEquals(result.getSessionToken(), expected.getSessionToken());
+ assertEquals(result.getExpiration(), expected.getExpiration());
+ }
+
+ public TemporaryCredentials expected() {
+ return TemporaryCredentials.builder()
+ .accessKeyId("AKIAIOSFODNN7EXAMPLE")
+ .secretAccessKey("wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY")
+ .sessionToken("AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT")
+ .expiration(new SimpleDateFormatDateService().iso8601DateParse("2011-07-11T19:55:29.611Z")).build();
+ }
+
+}
diff --git a/labs/sts/src/test/resources/assume_role.xml b/labs/sts/src/test/resources/assume_role.xml
new file mode 100644
index 0000000000..442dc147c1
--- /dev/null
+++ b/labs/sts/src/test/resources/assume_role.xml
@@ -0,0 +1,18 @@
+
+
+
+ AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT
+ wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY
+ 2011-07-11T19:55:29.611Z
+ AKIAIOSFODNN7EXAMPLE
+
+
+ arn:aws:sts::123456789012:assumed-role/demo/Bob
+ ARO123EXAMPLE123:Bob
+
+ 6
+
+
+ c6104cbe-af31-11e0-8154-cbc7ccf896c7
+
+
diff --git a/labs/sts/src/test/resources/federation_token.xml b/labs/sts/src/test/resources/federation_token.xml
new file mode 100644
index 0000000000..651f559a04
--- /dev/null
+++ b/labs/sts/src/test/resources/federation_token.xml
@@ -0,0 +1,18 @@
+
+
+
+ AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT
+ wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY
+ 2011-07-11T19:55:29.611Z
+ AKIAIOSFODNN7EXAMPLE
+
+
+ arn:aws:sts::123456789012:federated-user/Bob
+ 123456789012:Bob
+
+ 6
+
+
+ c6104cbe-af31-11e0-8154-cbc7ccf896c7
+
+
\ No newline at end of file
diff --git a/labs/sts/src/test/resources/log4j.xml b/labs/sts/src/test/resources/log4j.xml
new file mode 100644
index 0000000000..7527432931
--- /dev/null
+++ b/labs/sts/src/test/resources/log4j.xml
@@ -0,0 +1,166 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/labs/sts/src/test/resources/session_token.xml b/labs/sts/src/test/resources/session_token.xml
new file mode 100644
index 0000000000..062ea2dfa7
--- /dev/null
+++ b/labs/sts/src/test/resources/session_token.xml
@@ -0,0 +1,13 @@
+
+
+
+ AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT
+ wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY
+ 2011-07-11T19:55:29.611Z
+ AKIAIOSFODNN7EXAMPLE
+
+
+
+ 58c5dbae-abef-11e0-8cfe-09039844ac7d
+
+
\ No newline at end of file