diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackAsyncClient.java
index baf433b5e1..0a983f7e41 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackAsyncClient.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackAsyncClient.java
@@ -34,6 +34,7 @@ import org.jclouds.cloudstack.features.NetworkAsyncClient;
import org.jclouds.cloudstack.features.OfferingAsyncClient;
import org.jclouds.cloudstack.features.SSHKeyPairAsyncClient;
import org.jclouds.cloudstack.features.SecurityGroupAsyncClient;
+import org.jclouds.cloudstack.features.SessionAsyncClient;
import org.jclouds.cloudstack.features.SnapshotAsyncClient;
import org.jclouds.cloudstack.features.TemplateAsyncClient;
import org.jclouds.cloudstack.features.VMGroupAsyncClient;
@@ -184,4 +185,10 @@ public interface CloudStackAsyncClient {
*/
@Delegate
SnapshotAsyncClient getSnapshotClient();
+
+ /**
+ * Provides asynchronous access to Sessions
+ */
+ @Delegate
+ SessionAsyncClient getSessionClient();
}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackClient.java
index 82741a32aa..fc153e06a3 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackClient.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackClient.java
@@ -18,8 +18,6 @@
*/
package org.jclouds.cloudstack;
-import java.util.concurrent.TimeUnit;
-
import org.jclouds.cloudstack.features.AccountClient;
import org.jclouds.cloudstack.features.AddressClient;
import org.jclouds.cloudstack.features.AsyncJobClient;
@@ -41,10 +39,13 @@ import org.jclouds.cloudstack.features.TemplateClient;
import org.jclouds.cloudstack.features.VMGroupClient;
import org.jclouds.cloudstack.features.VirtualMachineClient;
import org.jclouds.cloudstack.features.VolumeClient;
+import org.jclouds.cloudstack.features.SessionClient;
import org.jclouds.cloudstack.features.ZoneClient;
import org.jclouds.concurrent.Timeout;
import org.jclouds.rest.annotations.Delegate;
+import java.util.concurrent.TimeUnit;
+
/**
* Provides synchronous access to CloudStack.
*
@@ -187,4 +188,10 @@ public interface CloudStackClient {
*/
@Delegate
SnapshotClient getSnapshotClient();
+
+ /**
+ * Provides synchronous access to Sessions
+ */
+ @Delegate
+ SessionClient getSessionClient();
}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackPropertiesBuilder.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackPropertiesBuilder.java
index 0238bc0bac..61dafad385 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackPropertiesBuilder.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackPropertiesBuilder.java
@@ -18,12 +18,12 @@
*/
package org.jclouds.cloudstack;
-import static org.jclouds.Constants.PROPERTY_API_VERSION;
-import static org.jclouds.Constants.PROPERTY_ENDPOINT;
+import org.jclouds.PropertiesBuilder;
import java.util.Properties;
-import org.jclouds.PropertiesBuilder;
+import static org.jclouds.Constants.PROPERTY_API_VERSION;
+import static org.jclouds.Constants.PROPERTY_ENDPOINT;
/**
* Builds properties used in cloudstack Clients
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackRestClientModule.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackRestClientModule.java
index 68023513f3..999f7025b7 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackRestClientModule.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackRestClientModule.java
@@ -96,6 +96,8 @@ import org.jclouds.cloudstack.features.SSHKeyPairAsyncClient;
import org.jclouds.cloudstack.features.SSHKeyPairClient;
import org.jclouds.cloudstack.features.SecurityGroupAsyncClient;
import org.jclouds.cloudstack.features.SecurityGroupClient;
+import org.jclouds.cloudstack.features.SessionAsyncClient;
+import org.jclouds.cloudstack.features.SessionClient;
import org.jclouds.cloudstack.features.SnapshotAsyncClient;
import org.jclouds.cloudstack.features.SnapshotClient;
import org.jclouds.cloudstack.features.TemplateAsyncClient;
@@ -175,6 +177,7 @@ public class CloudStackRestClientModule extends RestClientModule {
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+
+ private String userName;
+ private long userId;
+ private String password;
+ private long domainId;
+ private long timeout;
+ private String accountName;
+ private String firstName;
+ private String lastName;
+ private Account.Type accountType;
+ private String timezone;
+ private String timezoneOffset;
+ private String sessionKey;
+ private String jSessionId;
+
+ public Builder copyOf(LoginResponse r) {
+ this.userName = r.userName;
+ this.userId = r.userId;
+ this.password = r.password;
+ this.domainId = r.domainId;
+ this.timeout = r.timeout;
+ this.accountName = r.accountName;
+ this.firstName = r.firstName;
+ this.lastName = r.lastName;
+ this.accountType = r.accountType;
+ this.timezone = r.timezone;
+ this.timezoneOffset = r.timezoneOffset;
+ this.sessionKey = r.sessionKey;
+ this.jSessionId = r.jSessionId;
+ return this;
+ }
+
+ public Builder userName(String userName) {
+ this.userName = userName;
+ return this;
+ }
+
+ public Builder userId(long userId) {
+ this.userId = userId;
+ return this;
+ }
+
+ public Builder password(String password) {
+ this.password = password;
+ return this;
+ }
+
+ public Builder domainId(long domainId) {
+ this.domainId = domainId;
+ return this;
+ }
+
+ public Builder timeout(long timeout) {
+ this.timeout = timeout;
+ return this;
+ }
+
+ public Builder accountName(String accountName) {
+ this.accountName = accountName;
+ return this;
+ }
+
+ public Builder firstName(String firstName) {
+ this.firstName = firstName;
+ return this;
+ }
+
+ public Builder lastName(String lastName) {
+ this.lastName = lastName;
+ return this;
+ }
+
+ public Builder accountType(Account.Type accountType) {
+ this.accountType = accountType;
+ return this;
+ }
+
+ public Builder timezone(String timezone) {
+ this.timezone = timezone;
+ return this;
+ }
+
+ public Builder timezoneOffset(String timezoneOffset) {
+ this.timezoneOffset = timezoneOffset;
+ return this;
+ }
+
+ public Builder sessionKey(String sessionKey) {
+ this.sessionKey = sessionKey;
+ return this;
+ }
+
+ public Builder jSessionId(String jSessionId) {
+ this.jSessionId = jSessionId;
+ return this;
+ }
+
+ public LoginResponse build() {
+ return new LoginResponse(userName, userId, password, domainId, timeout, accountName,
+ firstName, lastName, accountType, timezone, timezoneOffset, sessionKey, jSessionId);
+ }
+ }
+
+ // for deserialization
+ LoginResponse() { }
+
+ @SerializedName("username")
+ private String userName;
+ @SerializedName("userid")
+ private long userId;
+ private String password;
+ @SerializedName("domainid")
+ private long domainId;
+ private long timeout;
+ @SerializedName("account")
+ private String accountName;
+ @SerializedName("firstname")
+ private String firstName;
+ @SerializedName("lastname")
+ private String lastName;
+ @SerializedName("type")
+ private Account.Type accountType;
+ private String timezone;
+ @SerializedName("timezoneoffset")
+ private String timezoneOffset;
+ @SerializedName("sessionkey")
+ private String sessionKey;
+ private String jSessionId;
+
+ public LoginResponse(String userName, long userId, String password, long domainId, long timeout,
+ String accountName, String firstName, String lastName, Account.Type accountType,
+ String timezone, String timezoneOffset, String sessionKey, String jSessionId) {
+ this.userName = userName;
+ this.userId = userId;
+ this.password = password;
+ this.domainId = domainId;
+ this.timeout = timeout;
+ this.accountName = accountName;
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.accountType = accountType;
+ this.timezone = timezone;
+ this.timezoneOffset = timezoneOffset;
+ this.sessionKey = sessionKey;
+ this.jSessionId = jSessionId;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public long getUserId() {
+ return userId;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public long getDomainId() {
+ return domainId;
+ }
+
+ public long getTimeout() {
+ return timeout;
+ }
+
+ public String getAccountName() {
+ return accountName;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public Account.Type getAccountType() {
+ return accountType;
+ }
+
+ public String getTimezone() {
+ return timezone;
+ }
+
+ public String getTimezoneOffset() {
+ return timezoneOffset;
+ }
+
+ public String getSessionKey() {
+ return sessionKey;
+ }
+
+ public String getJSessionId() {
+ return jSessionId;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ LoginResponse loginResponse = (LoginResponse) o;
+
+ if (domainId != loginResponse.domainId) return false;
+ if (timeout != loginResponse.timeout) return false;
+ if (userId != loginResponse.userId) return false;
+ if (accountName != null ? !accountName.equals(loginResponse.accountName) : loginResponse.accountName != null) return false;
+ if (accountType != loginResponse.accountType) return false;
+ if (firstName != null ? !firstName.equals(loginResponse.firstName) : loginResponse.firstName != null) return false;
+ if (lastName != null ? !lastName.equals(loginResponse.lastName) : loginResponse.lastName != null) return false;
+ if (password != null ? !password.equals(loginResponse.password) : loginResponse.password != null) return false;
+ if (sessionKey != null ? !sessionKey.equals(loginResponse.sessionKey) : loginResponse.sessionKey != null) return false;
+ if (timezone != null ? !timezone.equals(loginResponse.timezone) : loginResponse.timezone != null) return false;
+ if (timezoneOffset != null ? !timezoneOffset.equals(loginResponse.timezoneOffset) : loginResponse.timezoneOffset != null)
+ return false;
+ if (userName != null ? !userName.equals(loginResponse.userName) : loginResponse.userName != null) return false;
+ if (jSessionId != null ? !jSessionId.equals(loginResponse.jSessionId) : loginResponse.jSessionId != null) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = userName != null ? userName.hashCode() : 0;
+ result = 31 * result + (int) (userId ^ (userId >>> 32));
+ result = 31 * result + (password != null ? password.hashCode() : 0);
+ result = 31 * result + (int) (domainId ^ (domainId >>> 32));
+ result = 31 * result + (int) (timeout ^ (timeout >>> 32));
+ result = 31 * result + (accountName != null ? accountName.hashCode() : 0);
+ result = 31 * result + (firstName != null ? firstName.hashCode() : 0);
+ result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
+ result = 31 * result + (accountType != null ? accountType.hashCode() : 0);
+ result = 31 * result + (timezone != null ? timezone.hashCode() : 0);
+ result = 31 * result + (timezoneOffset != null ? timezoneOffset.hashCode() : 0);
+ result = 31 * result + (sessionKey != null ? sessionKey.hashCode() : 0);
+ result = 31 * result + (jSessionId != null ? jSessionId.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "LoginResponse{" +
+ "userName='" + userName + '\'' +
+ ", userId=" + userId +
+ ", password='" + password + '\'' +
+ ", domainId=" + domainId +
+ ", timeout=" + timeout +
+ ", accountName='" + accountName + '\'' +
+ ", firstName='" + firstName + '\'' +
+ ", lastName='" + lastName + '\'' +
+ ", accountType=" + accountType +
+ ", timezone='" + timezone + '\'' +
+ ", timezoneOffset='" + timezoneOffset + '\'' +
+ ", sessionKey='" + sessionKey + '\'' +
+ ", jSessionId='" + jSessionId + '\'' +
+ '}';
+ }
+
+ @Override
+ public int compareTo(LoginResponse arg0) {
+ return sessionKey.compareTo(arg0.getSessionKey());
+ }
+
+}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/SessionAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/SessionAsyncClient.java
new file mode 100644
index 0000000000..452e6a3a76
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/SessionAsyncClient.java
@@ -0,0 +1,78 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.cloudstack.features;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.jclouds.cloudstack.domain.Account;
+import org.jclouds.cloudstack.domain.LoginResponse;
+import org.jclouds.cloudstack.functions.ParseLoginResponseFromHttpResponse;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.QueryParams;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.SelectJson;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.CookieParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+
+/**
+ * Provides asynchronous access to Cloudstack Sessions
+ *
+ *
+ * @see org.jclouds.cloudstack.features.SessionClient
+ * @see
+ * @author Andrei Savu
+ */
+@QueryParams(keys = "response", values = "json")
+public interface SessionAsyncClient {
+
+ /**
+ * @see SessionClient#loginUserInDomainWithHashOfPassword
+ */
+ @GET
+ @QueryParams(keys = "command", values = "login")
+ @ResponseParser(ParseLoginResponseFromHttpResponse.class)
+ @Consumes(MediaType.APPLICATION_JSON)
+ @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+ ListenableFuture loginUserInDomainWithHashOfPassword(@QueryParam("username") String userName,
+ @QueryParam("domain") String domain, @QueryParam("password") String hashedPassword);
+
+ /**
+ * @see SessionClient#getAccountByNameUsingSession
+ */
+ @GET
+ @QueryParams(keys = "comand", values = "listAccounts")
+ @SelectJson("account")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+ ListenableFuture getAccountByNameUsingSession(@QueryParam("name") String accountName,
+ @QueryParam("sessionkey") String sessionKey, @CookieParam("JSESSIONID") String jSessionId);
+
+ /**
+ * @see SessionClient#logoutUser
+ */
+ @GET
+ @QueryParams(keys = "command", values = "logout")
+ @ExceptionParser(ReturnVoidOnNotFoundOr404.class)
+ ListenableFuture logoutUser(@QueryParam("sessionkey") String sessionKey);
+}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/SessionClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/SessionClient.java
new file mode 100644
index 0000000000..f21239873e
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/SessionClient.java
@@ -0,0 +1,77 @@
+/**
+ * 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.cloudstack.features;
+
+import org.jclouds.cloudstack.domain.Account;
+import org.jclouds.cloudstack.domain.LoginResponse;
+import org.jclouds.concurrent.Timeout;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Provides synchronous access to CloudStack Sessions
+ *
+ *
+ * @see
+ * @author Andrei Savu
+ */
+@Timeout(duration = 120, timeUnit = TimeUnit.SECONDS)
+public interface SessionClient {
+
+ /**
+ * Logs a user into Cloudstack. A successful login attempt will generate a JSESSIONID
+ * cookie value that can be passed in subsequent Query command calls until the "logout"
+ * command has been issued or the session has expired.
+ *
+ *
+ *
+ * @param userName
+ * user account name
+ * @param domain
+ * domain name, if empty defaults to ROOT
+ * @param hashedPassword
+ * hashed password (by default MD5)
+ * @return
+ * login response with session key or null
+ */
+ LoginResponse loginUserInDomainWithHashOfPassword(String userName, String domain, String hashedPassword);
+
+ /**
+ * Retrieve an account by name using the session key for login
+ *
+ * @param accountName
+ * account name
+ * @param sessionKey
+ * a valid session key
+ * @param jSessionId
+ * the JSESSIONID cookie returned by the server
+ * @return
+ * account instance or null
+ */
+ Account getAccountByNameUsingSession(String accountName, String sessionKey, String jSessionId);
+
+ /**
+ * Logs out the user by invalidating the session key
+ *
+ * @param sessionKey
+ * user session key
+ */
+ void logoutUser(String sessionKey);
+
+}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/functions/ParseLoginResponseFromHttpResponse.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/functions/ParseLoginResponseFromHttpResponse.java
new file mode 100644
index 0000000000..557a2764ad
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/functions/ParseLoginResponseFromHttpResponse.java
@@ -0,0 +1,41 @@
+package org.jclouds.cloudstack.functions;
+
+import com.google.common.base.Function;
+import com.google.common.base.Splitter;
+import com.google.inject.Inject;
+import com.google.inject.TypeLiteral;
+import org.jclouds.cloudstack.domain.LoginResponse;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseFirstJsonValueNamed;
+import org.jclouds.json.internal.GsonWrapper;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.get;
+import static com.google.common.collect.Iterables.getOnlyElement;
+
+/**
+ * @author Andrei Savu
+ */
+public class ParseLoginResponseFromHttpResponse implements Function {
+
+ private ParseFirstJsonValueNamed parser;
+
+ @Inject
+ ParseLoginResponseFromHttpResponse(GsonWrapper gson) {
+ this.parser = new ParseFirstJsonValueNamed(checkNotNull(gson, "gsonWrapper"),
+ new TypeLiteral(){}, "loginresponse");
+ }
+
+ @Override
+ public LoginResponse apply(HttpResponse response) {
+ checkNotNull(response, "response");
+
+ LoginResponse login = parser.apply(response);
+ checkNotNull(login, "loginResponse");
+
+ String jSessionId = get(Splitter.on("=").split(get(Splitter.on(";").trimResults().split(
+ getOnlyElement(response.getHeaders().get("Set-Cookie"))), 0)), 1);
+
+ return LoginResponse.builder().copyOf(login).jSessionId(jSessionId).build();
+ }
+}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/util/ApiKeyPairs.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/util/ApiKeyPairs.java
new file mode 100644
index 0000000000..1846d22e80
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/util/ApiKeyPairs.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.cloudstack.util;
+
+import org.jclouds.cloudstack.domain.ApiKeyPair;
+
+import java.net.URI;
+
+/**
+ * @author Andrei Savu
+ */
+public class ApiKeyPairs {
+
+ /**
+ * Retrieve the API key pair for a given CloudStack user
+ *
+ * @param endpoint
+ * CloudStack API endpoint (e.g. http://72.52.126.25/client/api/)
+ * @param userName
+ * User account name
+ * @param password
+ * User password
+ * @param domain
+ * Domain name. If empty defaults to ROOT
+ * @return
+ */
+ public static ApiKeyPair getApiKeyPairForUser(URI endpoint, String userName, String password, String domain) {
+ return null;
+ }
+}
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/SessionClientLiveTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/SessionClientLiveTest.java
new file mode 100644
index 0000000000..1b44bf5edf
--- /dev/null
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/SessionClientLiveTest.java
@@ -0,0 +1,79 @@
+/**
+ * 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.cloudstack.features;
+
+import com.google.common.base.Predicate;
+import org.jclouds.cloudstack.domain.Account;
+import org.jclouds.cloudstack.domain.LoginResponse;
+import org.jclouds.cloudstack.domain.User;
+import org.testng.annotations.Test;
+
+import static com.google.common.collect.Iterables.find;
+import static org.jclouds.crypto.CryptoStreams.md5Hex;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.AssertJUnit.assertEquals;
+
+/**
+ * Tests behavior of {@code SessionClient}
+ *
+ * @author Andrei Savu
+ */
+@Test(groups = "live", singleThreaded = true, testName = "SessionClientLiveTest")
+public class SessionClientLiveTest extends BaseCloudStackClientLiveTest {
+
+ private final String USER = "jcloud";
+ private final String PLAIN_TEXT_PASSWORD = "jcl0ud";
+ private final String DOMAIN = "Partners/jCloud";
+
+ private LoginResponse login;
+
+ @Test(enabled = true)
+ public void testLoginWithHashOfPassword() throws Exception {
+ login = client.getSessionClient()
+ .loginUserInDomainWithHashOfPassword(USER, DOMAIN, md5Hex(PLAIN_TEXT_PASSWORD));
+
+ assertNotNull(login);
+ assertNotNull(login.getSessionKey());
+ assertNotNull(login.getJSessionId());
+ }
+
+ @Test(dependsOnMethods = "testLoginWithHashOfPassword")
+ public void testRetrieveUserInfoWithSessionKey() throws Exception {
+ Account account = client.getSessionClient().getAccountByNameUsingSession(
+ login.getAccountName(), login.getSessionKey(), login.getJSessionId());
+
+ assertNotNull(account);
+ assertEquals(account.getName(), login.getAccountName());
+
+ User currentUser = find(account.getUsers(), new Predicate() {
+ @Override
+ public boolean apply(User user) {
+ return user.getId() == login.getUserId();
+ }
+ });
+ assertNotNull(currentUser);
+ assertEquals(currentUser.getName(), login.getUserName());
+ assertEquals(currentUser.getDomainId(), login.getDomainId());
+ }
+
+ @Test(dependsOnMethods = "testRetrieveUserInfoWithSessionKey")
+ public void testLogout() throws Exception {
+ client.getSessionClient().logoutUser(login.getSessionKey());
+ }
+}
diff --git a/core/src/main/java/org/jclouds/crypto/CryptoStreams.java b/core/src/main/java/org/jclouds/crypto/CryptoStreams.java
index ad3ae8e280..6c810cae10 100644
--- a/core/src/main/java/org/jclouds/crypto/CryptoStreams.java
+++ b/core/src/main/java/org/jclouds/crypto/CryptoStreams.java
@@ -18,8 +18,17 @@
*/
package org.jclouds.crypto;
-import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.annotations.Beta;
+import com.google.common.base.Charsets;
+import com.google.common.base.Throwables;
+import com.google.common.io.ByteProcessor;
+import com.google.common.io.ByteStreams;
+import com.google.common.io.InputSupplier;
+import org.jclouds.encryption.internal.Base64;
+import org.jclouds.io.InputSuppliers;
+import javax.crypto.Mac;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -28,17 +37,7 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
-import javax.crypto.Mac;
-
-import org.jclouds.encryption.internal.Base64;
-import org.jclouds.io.InputSuppliers;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Charsets;
-import com.google.common.base.Throwables;
-import com.google.common.io.ByteProcessor;
-import com.google.common.io.ByteStreams;
-import com.google.common.io.InputSupplier;
+import static com.google.common.base.Preconditions.checkNotNull;
/**
* functions related to but not in {@link com.google.common.io.ByteStreams}
@@ -89,6 +88,18 @@ public class CryptoStreams {
return hex(md5(supplier));
}
+ /**
+ * @see #md5Hex
+ */
+ public static String md5Hex(final String in) throws IOException {
+ return md5Hex(new InputSupplier() {
+ @Override
+ public InputStream getInput() throws IOException {
+ return new ByteArrayInputStream(in.getBytes());
+ }
+ });
+ }
+
/**
* @see #md5
* @see #base64