revised session test to be performed offline with expect test and added a couple missing fields

This commit is contained in:
Adrian Cole 2012-01-31 17:13:51 -08:00
parent b3254b31e6
commit be453c6650
7 changed files with 286 additions and 207 deletions

View File

@ -23,7 +23,7 @@ import com.google.gson.annotations.SerializedName;
/** /**
* Representation of the login API call response * Representation of the login API call response
* *
* @author Andrei Savu * @author Andrei Savu
*/ */
public class LoginResponse implements Comparable<LoginResponse> { public class LoginResponse implements Comparable<LoginResponse> {
@ -34,11 +34,12 @@ public class LoginResponse implements Comparable<LoginResponse> {
public static class Builder { public static class Builder {
private String userName; private String username;
private long userId; private long userId;
private String password; private String password;
private long domainId; private long domainId;
private long timeout; private long timeout;
private boolean registered;
private String accountName; private String accountName;
private String firstName; private String firstName;
private String lastName; private String lastName;
@ -47,13 +48,14 @@ public class LoginResponse implements Comparable<LoginResponse> {
private String timezoneOffset; private String timezoneOffset;
private String sessionKey; private String sessionKey;
private String jSessionId; private String jSessionId;
public Builder copyOf(LoginResponse r) { public Builder copyOf(LoginResponse r) {
this.userName = r.userName; this.username = r.username;
this.userId = r.userId; this.userId = r.userId;
this.password = r.password; this.password = r.password;
this.domainId = r.domainId; this.domainId = r.domainId;
this.timeout = r.timeout; this.timeout = r.timeout;
this.registered = r.registered;
this.accountName = r.accountName; this.accountName = r.accountName;
this.firstName = r.firstName; this.firstName = r.firstName;
this.lastName = r.lastName; this.lastName = r.lastName;
@ -65,111 +67,114 @@ public class LoginResponse implements Comparable<LoginResponse> {
return this; return this;
} }
public Builder userName(String userName) { public Builder username(String username) {
this.userName = userName; this.username = username;
return this; return this;
} }
public Builder userId(long userId) { public Builder userId(long userId) {
this.userId = userId; this.userId = userId;
return this; return this;
} }
public Builder password(String password) { public Builder password(String password) {
this.password = password; this.password = password;
return this; return this;
} }
public Builder domainId(long domainId) { public Builder domainId(long domainId) {
this.domainId = domainId; this.domainId = domainId;
return this; return this;
} }
public Builder timeout(long timeout) { public Builder timeout(long timeout) {
this.timeout = timeout; this.timeout = timeout;
return this; return this;
} }
public Builder registered(boolean registered) {
this.registered = registered;
return this;
}
public Builder accountName(String accountName) { public Builder accountName(String accountName) {
this.accountName = accountName; this.accountName = accountName;
return this; return this;
} }
public Builder firstName(String firstName) { public Builder firstName(String firstName) {
this.firstName = firstName; this.firstName = firstName;
return this; return this;
} }
public Builder lastName(String lastName) { public Builder lastName(String lastName) {
this.lastName = lastName; this.lastName = lastName;
return this; return this;
} }
public Builder accountType(Account.Type accountType) { public Builder accountType(Account.Type accountType) {
this.accountType = accountType; this.accountType = accountType;
return this; return this;
} }
public Builder timezone(String timezone) { public Builder timezone(String timezone) {
this.timezone = timezone; this.timezone = timezone;
return this; return this;
} }
public Builder timezoneOffset(String timezoneOffset) { public Builder timezoneOffset(String timezoneOffset) {
this.timezoneOffset = timezoneOffset; this.timezoneOffset = timezoneOffset;
return this; return this;
} }
public Builder sessionKey(String sessionKey) { public Builder sessionKey(String sessionKey) {
this.sessionKey = sessionKey; this.sessionKey = sessionKey;
return this; return this;
} }
public Builder jSessionId(String jSessionId) { public Builder jSessionId(String jSessionId) {
this.jSessionId = jSessionId; this.jSessionId = jSessionId;
return this; return this;
} }
public LoginResponse build() { public LoginResponse build() {
return new LoginResponse(userName, userId, password, domainId, timeout, accountName, return new LoginResponse(username, userId, password, domainId, timeout, registered, accountName, firstName,
firstName, lastName, accountType, timezone, timezoneOffset, sessionKey, jSessionId); lastName, accountType, timezone, timezoneOffset, sessionKey, jSessionId);
} }
} }
// for deserialization private final String username;
LoginResponse() { }
@SerializedName("username")
private String userName;
@SerializedName("userid") @SerializedName("userid")
private long userId; private final long userId;
private String password; private final String password;
@SerializedName("domainid") @SerializedName("domainid")
private long domainId; private final long domainId;
private long timeout; private final long timeout;
private final boolean registered;
@SerializedName("account") @SerializedName("account")
private String accountName; private final String accountName;
@SerializedName("firstname") @SerializedName("firstname")
private String firstName; private final String firstName;
@SerializedName("lastname") @SerializedName("lastname")
private String lastName; private final String lastName;
@SerializedName("type") @SerializedName("type")
private Account.Type accountType; private final Account.Type accountType;
private String timezone; private final String timezone;
@SerializedName("timezoneoffset") @SerializedName("timezoneoffset")
private String timezoneOffset; private final String timezoneOffset;
@SerializedName("sessionkey") @SerializedName("sessionkey")
private String sessionKey; private final String sessionKey;
private String jSessionId; private final String jSessionId;
public LoginResponse(String userName, long userId, String password, long domainId, long timeout, public LoginResponse(String username, long userId, String password, long domainId, long timeout, boolean registered,
String accountName, String firstName, String lastName, Account.Type accountType, String accountName, String firstName, String lastName, Account.Type accountType, String timezone,
String timezone, String timezoneOffset, String sessionKey, String jSessionId) { String timezoneOffset, String sessionKey, String jSessionId) {
this.userName = userName; this.username = username;
this.userId = userId; this.userId = userId;
this.password = password; this.password = password;
this.domainId = domainId; this.domainId = domainId;
this.timeout = timeout; this.timeout = timeout;
this.registered = registered;
this.accountName = accountName; this.accountName = accountName;
this.firstName = firstName; this.firstName = firstName;
this.lastName = lastName; this.lastName = lastName;
@ -180,8 +185,8 @@ public class LoginResponse implements Comparable<LoginResponse> {
this.jSessionId = jSessionId; this.jSessionId = jSessionId;
} }
public String getUserName() { public String getUsername() {
return userName; return username;
} }
public long getUserId() { public long getUserId() {
@ -200,6 +205,10 @@ public class LoginResponse implements Comparable<LoginResponse> {
return timeout; return timeout;
} }
public boolean isRegistered() {
return registered;
}
public String getAccountName() { public String getAccountName() {
return accountName; return accountName;
} }
@ -227,71 +236,110 @@ public class LoginResponse implements Comparable<LoginResponse> {
public String getSessionKey() { public String getSessionKey() {
return sessionKey; return sessionKey;
} }
public String getJSessionId() { public String getJSessionId() {
return jSessionId; return jSessionId;
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object obj) {
if (this == o) return true; if (this == obj)
if (o == null || getClass() != o.getClass()) return false; return true;
if (obj == null)
LoginResponse loginResponse = (LoginResponse) o; return false;
if (getClass() != obj.getClass())
if (domainId != loginResponse.domainId) return false; return false;
if (timeout != loginResponse.timeout) return false; LoginResponse other = (LoginResponse) obj;
if (userId != loginResponse.userId) return false; if (accountName == null) {
if (accountName != null ? !accountName.equals(loginResponse.accountName) : loginResponse.accountName != null) return false; if (other.accountName != null)
if (accountType != loginResponse.accountType) return false; return false;
if (firstName != null ? !firstName.equals(loginResponse.firstName) : loginResponse.firstName != null) return false; } else if (!accountName.equals(other.accountName))
if (lastName != null ? !lastName.equals(loginResponse.lastName) : loginResponse.lastName != null) return false; return false;
if (password != null ? !password.equals(loginResponse.password) : loginResponse.password != null) return false; if (accountType == null) {
if (sessionKey != null ? !sessionKey.equals(loginResponse.sessionKey) : loginResponse.sessionKey != null) return false; if (other.accountType != null)
if (timezone != null ? !timezone.equals(loginResponse.timezone) : loginResponse.timezone != null) return false; return false;
if (timezoneOffset != null ? !timezoneOffset.equals(loginResponse.timezoneOffset) : loginResponse.timezoneOffset != null) } 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; 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; return true;
} }
@Override @Override
public int hashCode() { public int hashCode() {
int result = userName != null ? userName.hashCode() : 0; final int prime = 31;
result = 31 * result + (int) (userId ^ (userId >>> 32)); int result = 1;
result = 31 * result + (password != null ? password.hashCode() : 0); result = prime * result + ((accountName == null) ? 0 : accountName.hashCode());
result = 31 * result + (int) (domainId ^ (domainId >>> 32)); result = prime * result + ((accountType == null) ? 0 : accountType.hashCode());
result = 31 * result + (int) (timeout ^ (timeout >>> 32)); result = prime * result + (int) (domainId ^ (domainId >>> 32));
result = 31 * result + (accountName != null ? accountName.hashCode() : 0); result = prime * result + ((firstName == null) ? 0 : firstName.hashCode());
result = 31 * result + (firstName != null ? firstName.hashCode() : 0); result = prime * result + ((jSessionId == null) ? 0 : jSessionId.hashCode());
result = 31 * result + (lastName != null ? lastName.hashCode() : 0); result = prime * result + ((lastName == null) ? 0 : lastName.hashCode());
result = 31 * result + (accountType != null ? accountType.hashCode() : 0); result = prime * result + ((password == null) ? 0 : password.hashCode());
result = 31 * result + (timezone != null ? timezone.hashCode() : 0); result = prime * result + (registered ? 1231 : 1237);
result = 31 * result + (timezoneOffset != null ? timezoneOffset.hashCode() : 0); result = prime * result + ((sessionKey == null) ? 0 : sessionKey.hashCode());
result = 31 * result + (sessionKey != null ? sessionKey.hashCode() : 0); result = prime * result + (int) (timeout ^ (timeout >>> 32));
result = 31 * result + (jSessionId != null ? jSessionId.hashCode() : 0); 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; return result;
} }
@Override @Override
public String toString() { public String toString() {
return "LoginResponse{" + return "LoginResponse{" + "username='" + username + '\'' + ", userId=" + userId + ", password='" + password
"userName='" + userName + '\'' + + '\'' + ", domainId=" + domainId + ", timeout=" + timeout + ", registered=" + registered
", userId=" + userId + + ", accountName='" + accountName + '\'' + ", firstName='" + firstName + '\'' + ", lastName='"
", password='" + password + '\'' + + lastName + '\'' + ", accountType=" + accountType + ", timezone='" + timezone + '\''
", domainId=" + domainId + + ", timezoneOffset='" + timezoneOffset + '\'' + ", sessionKey='" + sessionKey + '\'' + ", jSessionId='"
", timeout=" + timeout + + jSessionId + '\'' + '}';
", accountName='" + accountName + '\'' +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", accountType=" + accountType +
", timezone='" + timezone + '\'' +
", timezoneOffset='" + timezoneOffset + '\'' +
", sessionKey='" + sessionKey + '\'' +
", jSessionId='" + jSessionId + '\'' +
'}';
} }
@Override @Override

View File

@ -18,22 +18,20 @@
*/ */
package org.jclouds.cloudstack.features; package org.jclouds.cloudstack.features;
import com.google.common.util.concurrent.ListenableFuture; import javax.ws.rs.Consumes;
import org.jclouds.cloudstack.domain.Account; 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.domain.LoginResponse;
import org.jclouds.cloudstack.functions.ParseLoginResponseFromHttpResponse; import org.jclouds.cloudstack.functions.ParseLoginResponseFromHttpResponse;
import org.jclouds.rest.annotations.ExceptionParser; import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.QueryParams; import org.jclouds.rest.annotations.QueryParams;
import org.jclouds.rest.annotations.ResponseParser; import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.rest.annotations.SelectJson;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404; import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
import javax.ws.rs.Consumes; import com.google.common.util.concurrent.ListenableFuture;
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 * Provides asynchronous access to Cloudstack Sessions
@ -57,17 +55,6 @@ public interface SessionAsyncClient {
ListenableFuture<LoginResponse> loginUserInDomainWithHashOfPassword(@QueryParam("username") String userName, ListenableFuture<LoginResponse> loginUserInDomainWithHashOfPassword(@QueryParam("username") String userName,
@QueryParam("domain") String domain, @QueryParam("password") String hashedPassword); @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<Account> getAccountByNameUsingSession(@QueryParam("name") String accountName,
@QueryParam("sessionkey") String sessionKey, @CookieParam("JSESSIONID") String jSessionId);
/** /**
* @see SessionClient#logoutUser * @see SessionClient#logoutUser
*/ */

View File

@ -18,12 +18,11 @@
*/ */
package org.jclouds.cloudstack.features; 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.cloudstack.domain.LoginResponse;
import org.jclouds.concurrent.Timeout; import org.jclouds.concurrent.Timeout;
import java.util.concurrent.TimeUnit;
/** /**
* Provides synchronous access to CloudStack Sessions * Provides synchronous access to CloudStack Sessions
* <p/> * <p/>
@ -52,19 +51,6 @@ public interface SessionClient {
*/ */
LoginResponse loginUserInDomainWithHashOfPassword(String userName, String domain, String hashedPassword); 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 * Logs out the user by invalidating the session key

View File

@ -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 <a href="http://docs.cloud.com/CloudStack_Documentation/Customizing_the_CloudStack_UI#Cross_Site_Request_Forgery_%28CSRF%29"
* />
*/
@Singleton
public class AddSessionKeyAndJSessionIdToRequest implements HttpRequestFilter {
private final Supplier<LoginResponse> loginResponseSupplier;
private final Provider<UriBuilder> uriBuilderProvider;
@Inject
public AddSessionKeyAndJSessionIdToRequest(Supplier<LoginResponse> loginResponseSupplier,
Provider<UriBuilder> 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;
}
}

View File

@ -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<SessionClient> {
@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.<String, String>builder()
.put("Accept", "application/json")
.build())
.build();
String jSessionId = "90DD65D13AEAA590ECCA312D150B9F6D";
SessionClient client = requestSendsResponse(request,
HttpResponse.builder()
.statusCode(200)
.headers(
ImmutableMultimap.<String, String>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();
}
}

View File

@ -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<User>() {
@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());
}
}

View File

@ -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" } }