diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/LoginResponse.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/LoginResponse.java index 351b9f7f4d..9fc2474a2f 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/LoginResponse.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/LoginResponse.java @@ -23,7 +23,7 @@ import com.google.gson.annotations.SerializedName; /** * Representation of the login API call response - * + * * @author Andrei Savu */ public class LoginResponse implements Comparable { @@ -34,11 +34,12 @@ public class LoginResponse implements Comparable { public static class Builder { - private String userName; + private String username; private long userId; private String password; private long domainId; private long timeout; + private boolean registered; private String accountName; private String firstName; private String lastName; @@ -47,13 +48,14 @@ public class LoginResponse implements Comparable { private String timezoneOffset; private String sessionKey; private String jSessionId; - + public Builder copyOf(LoginResponse r) { - this.userName = r.userName; + this.username = r.username; this.userId = r.userId; this.password = r.password; this.domainId = r.domainId; this.timeout = r.timeout; + this.registered = r.registered; this.accountName = r.accountName; this.firstName = r.firstName; this.lastName = r.lastName; @@ -65,111 +67,114 @@ public class LoginResponse implements Comparable { return this; } - public Builder userName(String userName) { - this.userName = userName; + public Builder username(String username) { + this.username = username; return this; } - - public Builder userId(long userId) { + + 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 registered(boolean registered) { + this.registered = registered; + 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); + return new LoginResponse(username, userId, password, domainId, timeout, registered, accountName, firstName, + lastName, accountType, timezone, timezoneOffset, sessionKey, jSessionId); } } - // for deserialization - LoginResponse() { } - - @SerializedName("username") - private String userName; + private final String username; @SerializedName("userid") - private long userId; - private String password; + private final long userId; + private final String password; @SerializedName("domainid") - private long domainId; - private long timeout; + private final long domainId; + private final long timeout; + private final boolean registered; @SerializedName("account") - private String accountName; + private final String accountName; @SerializedName("firstname") - private String firstName; + private final String firstName; @SerializedName("lastname") - private String lastName; + private final String lastName; @SerializedName("type") - private Account.Type accountType; - private String timezone; + private final Account.Type accountType; + private final String timezone; @SerializedName("timezoneoffset") - private String timezoneOffset; + private final String timezoneOffset; @SerializedName("sessionkey") - private String sessionKey; - private String jSessionId; + private final String sessionKey; + private final 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; + public LoginResponse(String username, long userId, String password, long domainId, long timeout, boolean registered, + 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.registered = registered; this.accountName = accountName; this.firstName = firstName; this.lastName = lastName; @@ -180,8 +185,8 @@ public class LoginResponse implements Comparable { this.jSessionId = jSessionId; } - public String getUserName() { - return userName; + public String getUsername() { + return username; } public long getUserId() { @@ -200,6 +205,10 @@ public class LoginResponse implements Comparable { return timeout; } + public boolean isRegistered() { + return registered; + } + public String getAccountName() { return accountName; } @@ -227,71 +236,110 @@ public class LoginResponse implements Comparable { 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) + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + LoginResponse other = (LoginResponse) obj; + if (accountName == null) { + if (other.accountName != null) + return false; + } else if (!accountName.equals(other.accountName)) + return false; + if (accountType == null) { + if (other.accountType != null) + return false; + } else if (!accountType.equals(other.accountType)) + return false; + if (domainId != other.domainId) + return false; + if (firstName == null) { + if (other.firstName != null) + return false; + } else if (!firstName.equals(other.firstName)) + return false; + if (jSessionId == null) { + if (other.jSessionId != null) + return false; + } else if (!jSessionId.equals(other.jSessionId)) + return false; + if (lastName == null) { + if (other.lastName != null) + return false; + } else if (!lastName.equals(other.lastName)) + return false; + if (password == null) { + if (other.password != null) + return false; + } else if (!password.equals(other.password)) + return false; + if (registered != other.registered) + return false; + if (sessionKey == null) { + if (other.sessionKey != null) + return false; + } else if (!sessionKey.equals(other.sessionKey)) + return false; + if (timeout != other.timeout) + return false; + if (timezone == null) { + if (other.timezone != null) + return false; + } else if (!timezone.equals(other.timezone)) + return false; + if (timezoneOffset == null) { + if (other.timezoneOffset != null) + return false; + } else if (!timezoneOffset.equals(other.timezoneOffset)) + return false; + if (userId != other.userId) + return false; + if (username == null) { + if (other.username != null) + return false; + } else if (!username.equals(other.username)) 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); + final int prime = 31; + int result = 1; + result = prime * result + ((accountName == null) ? 0 : accountName.hashCode()); + result = prime * result + ((accountType == null) ? 0 : accountType.hashCode()); + result = prime * result + (int) (domainId ^ (domainId >>> 32)); + result = prime * result + ((firstName == null) ? 0 : firstName.hashCode()); + result = prime * result + ((jSessionId == null) ? 0 : jSessionId.hashCode()); + result = prime * result + ((lastName == null) ? 0 : lastName.hashCode()); + result = prime * result + ((password == null) ? 0 : password.hashCode()); + result = prime * result + (registered ? 1231 : 1237); + result = prime * result + ((sessionKey == null) ? 0 : sessionKey.hashCode()); + result = prime * result + (int) (timeout ^ (timeout >>> 32)); + result = prime * result + ((timezone == null) ? 0 : timezone.hashCode()); + result = prime * result + ((timezoneOffset == null) ? 0 : timezoneOffset.hashCode()); + result = prime * result + (int) (userId ^ (userId >>> 32)); + result = prime * result + ((username == null) ? 0 : username.hashCode()); 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 + '\'' + - '}'; + return "LoginResponse{" + "username='" + username + '\'' + ", userId=" + userId + ", password='" + password + + '\'' + ", domainId=" + domainId + ", timeout=" + timeout + ", registered=" + registered + + ", accountName='" + accountName + '\'' + ", firstName='" + firstName + '\'' + ", lastName='" + + lastName + '\'' + ", accountType=" + accountType + ", timezone='" + timezone + '\'' + + ", timezoneOffset='" + timezoneOffset + '\'' + ", sessionKey='" + sessionKey + '\'' + ", jSessionId='" + + jSessionId + '\'' + '}'; } @Override 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 index 452e6a3a76..3ad40510bd 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/SessionAsyncClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/SessionAsyncClient.java @@ -18,22 +18,20 @@ */ package org.jclouds.cloudstack.features; -import com.google.common.util.concurrent.ListenableFuture; -import org.jclouds.cloudstack.domain.Account; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + 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; +import com.google.common.util.concurrent.ListenableFuture; /** * Provides asynchronous access to Cloudstack Sessions @@ -57,17 +55,6 @@ public interface SessionAsyncClient { 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 */ 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 index f21239873e..6d72b46fbf 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/SessionClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/SessionClient.java @@ -18,12 +18,11 @@ */ package org.jclouds.cloudstack.features; -import org.jclouds.cloudstack.domain.Account; +import java.util.concurrent.TimeUnit; + import org.jclouds.cloudstack.domain.LoginResponse; import org.jclouds.concurrent.Timeout; -import java.util.concurrent.TimeUnit; - /** * Provides synchronous access to CloudStack Sessions *

@@ -52,19 +51,6 @@ public interface SessionClient { */ 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 diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/filters/AddSessionKeyAndJSessionIdToRequest.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/filters/AddSessionKeyAndJSessionIdToRequest.java new file mode 100644 index 0000000000..182aa9abeb --- /dev/null +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/filters/AddSessionKeyAndJSessionIdToRequest.java @@ -0,0 +1,48 @@ +package org.jclouds.cloudstack.filters; + +import static org.jclouds.http.utils.ModifyRequest.addQueryParam; +import static org.jclouds.http.utils.ModifyRequest.replaceHeader; + +import javax.inject.Inject; +import javax.inject.Provider; +import javax.inject.Singleton; +import javax.ws.rs.core.UriBuilder; + +import org.jclouds.cloudstack.domain.LoginResponse; +import org.jclouds.http.HttpException; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpRequestFilter; + +import com.google.common.base.Supplier; +import com.google.common.net.HttpHeaders; + +/** + * + * @author Andrei Savu, Adrian Cole + * @see + */ +@Singleton +public class AddSessionKeyAndJSessionIdToRequest implements HttpRequestFilter { + + private final Supplier loginResponseSupplier; + private final Provider uriBuilderProvider; + + @Inject + public AddSessionKeyAndJSessionIdToRequest(Supplier loginResponseSupplier, + Provider uriBuilderProvider) { + this.loginResponseSupplier = loginResponseSupplier; + this.uriBuilderProvider = uriBuilderProvider; + } + + @Override + public HttpRequest filter(HttpRequest request) throws HttpException { + LoginResponse loginResponse = loginResponseSupplier.get(); + + request = replaceHeader(request, HttpHeaders.COOKIE, "JSESSIONID=" + loginResponse.getJSessionId()); + request = addQueryParam(request, "sessionkey", loginResponse.getSessionKey(), uriBuilderProvider.get()); + return request; + + } + +} \ No newline at end of file diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/SessionClientExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/SessionClientExpectTest.java new file mode 100644 index 0000000000..c58f3ce0f4 --- /dev/null +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/SessionClientExpectTest.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.cloudstack.features; + +import static org.jclouds.crypto.CryptoStreams.md5Hex; +import static org.testng.Assert.assertEquals; + +import java.io.IOException; +import java.net.URI; +import java.net.URLEncoder; + +import org.jclouds.cloudstack.CloudStackContext; +import org.jclouds.cloudstack.domain.Account; +import org.jclouds.cloudstack.domain.LoginResponse; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMultimap; + +/** + * Tests behavior of {@code SessionClient} + * + * @author Andrei Savu + */ +@Test(groups = "live", singleThreaded = true, testName = "SessionClientExpectTest") +public class SessionClientExpectTest extends BaseCloudStackRestClientExpectTest { + + @SuppressWarnings("deprecation") + public void testLoginWhenResponseIs2xxIncludesJSessionId() throws IOException { + String domain = "Partners/jCloud"; + String user = "jcloud"; + String password = "jcl0ud"; + String md5password = md5Hex(password); + + HttpRequest request = HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&command=login&" + + "username="+user+"&password=" + md5password+ "&domain=" + URLEncoder.encode(domain))) + .headers( + ImmutableMultimap.builder() + .put("Accept", "application/json") + .build()) + .build(); + + String jSessionId = "90DD65D13AEAA590ECCA312D150B9F6D"; + SessionClient client = requestSendsResponse(request, + HttpResponse.builder() + .statusCode(200) + .headers( + ImmutableMultimap.builder() + .put("Set-Cookie", "JSESSIONID="+jSessionId+"; Path=/client") + .build()) + .payload(payloadFromResource("/loginresponse.json")) + .build()); + + assertEquals(client.loginUserInDomainWithHashOfPassword(user, domain, md5password).toString(), + + LoginResponse.builder().timeout(1800).lastName("Kiran").registered(false).username("jcloud").firstName("Vijay") + .domainId(11).accountType(Account.Type.DOMAIN_ADMIN).userId(19).sessionKey( + "uYT4/MNiglgAKiZRQkvV8QP8gn0=").jSessionId(jSessionId).accountName("jcloud").build().toString()); + } + + //TODO: logout. + + + @Override + protected SessionClient clientFrom(CloudStackContext context) { + return context.getProviderSpecificContext().getApi().getSessionClient(); + } +} 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 deleted file mode 100644 index 1b44bf5edf..0000000000 --- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/SessionClientLiveTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/** - * 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/apis/cloudstack/src/test/resources/loginresponse.json b/apis/cloudstack/src/test/resources/loginresponse.json new file mode 100644 index 0000000000..41df202170 --- /dev/null +++ b/apis/cloudstack/src/test/resources/loginresponse.json @@ -0,0 +1 @@ +{ "loginresponse" : { "timeout" : "1800", "lastname" : "Kiran", "registered" : "false", "username" : "jcloud", "firstname" : "Vijay", "domainid" : "11", "type" : "2", "userid" : "19", "sessionkey" : "uYT4/MNiglgAKiZRQkvV8QP8gn0=", "account" : "jcloud" } } \ No newline at end of file