Java tutorial
// Dashboard: an Android front-end to the RightScale dashboard // Copyright (C) 2009 Tony Spataro <code@tracker.xeger.net> // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. package com.rightscale.provider.rest; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import org.apache.http.HttpException; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.HttpRequestInterceptor; import org.apache.http.HttpResponse; import org.apache.http.auth.AuthScope; import org.apache.http.auth.AuthState; import org.apache.http.auth.Credentials; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.protocol.ClientContext; import org.apache.http.cookie.Cookie; import org.apache.http.impl.auth.BasicScheme; import org.apache.http.impl.client.AbstractHttpClient; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.apache.http.protocol.ExecutionContext; import org.apache.http.protocol.HttpContext; import net.xeger.rest.AbstractResource; import net.xeger.rest.ProtocolError; import net.xeger.rest.RestAuthException; import net.xeger.rest.RestException; import net.xeger.rest.Session; import net.xeger.rest.client.*; import com.rightscale.provider.*; public class DashboardSession implements Session { static public final String LOGIN_PAGE_CANARY = "New RightScale Session"; private String _username, _password; private URI _baseURI; /** * Session cookie; only gets stored when a login request succeeds. Thus, the presence * of a session cookie in this variable doubles as an indicator that we are logged in. */ private Cookie _sessionCookie = null; public DashboardSession(String username, String password, String system) { _username = username; _password = password; try { _baseURI = new URI("https://" + system); } catch (URISyntaxException e) { throw new ProtocolError(e); } } public URI getBaseURI() { return _baseURI; } public void setCurrentAccount(String accountId) throws RestException { login(); try { URI switchUri = new URI(_baseURI.toString() + "/acct/" + accountId); HttpPut put = createPut(switchUri); StatefulClient client = createClient(); HttpResponse response = client.execute(put); String body = AbstractResource.readResponse(response.getEntity()); if (response.getStatusLine().getStatusCode() != 200 || body.contains(LOGIN_PAGE_CANARY)) { throw new RestAuthException("UI account-switch request failed", response.getStatusLine().getStatusCode()); } List<Cookie> cookies = client.getCookieStore().getCookies(); for (Cookie c : cookies) { if (c.getName().startsWith("rs_gbl")) { _sessionCookie = c; break; } } if (_sessionCookie == null) { throw new RestAuthException("UI account-switch response did not contain updated session cookie", 401); } } catch (Exception e) { //Nothing should go wrong here throw new DashboardError(e); } } public void login() throws RestException { if (_sessionCookie != null) { return; } if (_username == null || _password == null || _username.length() == 0 || _password.length() == 0) { throw new RestAuthException("Username or password not supplied", 401); } try { // Can't use accounts-API login because we don't necessarily know an account ID. // HACK: use UI login instead. URI loginUri = new URI(_baseURI.toString() + "/session"); HttpPost post = createPost(loginUri); List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>(); params.add(new BasicNameValuePair("email", _username)); params.add(new BasicNameValuePair("password", _password)); params.add(new BasicNameValuePair("login_type", "rs")); post.setEntity(new UrlEncodedFormEntity(params)); DefaultHttpClient client = new DefaultHttpClient(); HttpResponse response = client.execute(post); String body = AbstractResource.readResponse(response.getEntity()); if (response.getStatusLine().getStatusCode() != 200 || body.contains(LOGIN_PAGE_CANARY)) { throw new RestAuthException("UI login request failed", response.getStatusLine().getStatusCode()); } List<Cookie> cookies = client.getCookieStore().getCookies(); for (Cookie c : cookies) { if (c.getName().startsWith("rs_gbl")) { _sessionCookie = c; break; } } if (_sessionCookie == null) { throw new RestAuthException("UI login response did not contain session cookie", 401); } } catch (Exception e) { //Nothing should go wrong here throw new DashboardError(e); } } public void logout() { _sessionCookie = null; } /** * Create . */ public StatefulClient createClient() { StatefulClient client = createAnonymousClient(); if (_sessionCookie != null) { client.getCookieStore().addCookie(_sessionCookie); } //Add some useful behaviors to the stock HTTP client return new RetryClient(new SessionClient(client, this), 3); } public StatefulClient createBasicAuthClient() { StatefulClient client = createAnonymousClient(); //Wire up the client to perform HTTP basic authentication setupBasicAuth(client); //Add some useful behaviors to the stock HTTP client return new RetryClient(new SessionClient(client, this), 3); } /** * Create an anonymous, unauthenticated client. */ public StatefulClient createAnonymousClient() { DefaultHttpClient client = new DefaultHttpClient(); //Add some useful behaviors to the stock HTTP client return new RetryClient(client, 3); } public HttpGet createGet(URI uri) { HttpGet get = new HttpGet(uri.toString()); get.addHeader("Host", uri.getAuthority()); get.addHeader("Accept", "application/json,text/json,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"); get.addHeader("User-Agent", "com.rightscale.provider"); get.addHeader("X-API-Version", "1.0"); return get; } public HttpPost createPost(URI uri) { HttpPost post = new HttpPost(uri); post.addHeader("X-API-Version", "1.0"); return post; } public HttpPut createPut(URI uri) { HttpPut put = new HttpPut(uri); put.addHeader("X-API-Version", "1.0"); return put; } private void setupBasicAuth(StatefulClient client) { AuthScope authScope = new AuthScope(_baseURI.getHost(), AuthScope.ANY_PORT, AuthScope.ANY_REALM); UsernamePasswordCredentials creds = new UsernamePasswordCredentials(_username, _password); AbstractHttpClient realClient = (AbstractHttpClient) client.getRealClient(); realClient.getCredentialsProvider().setCredentials(authScope, creds); realClient.addRequestInterceptor(createBasicAuthInterceptor(), 0); } private HttpRequestInterceptor createBasicAuthInterceptor() { return new HttpRequestInterceptor() { public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException { AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE); CredentialsProvider credsProvider = (CredentialsProvider) context .getAttribute(ClientContext.CREDS_PROVIDER); HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST); if (authState.getAuthScheme() == null) { AuthScope authScope = new AuthScope(targetHost.getHostName(), targetHost.getPort()); Credentials creds = credsProvider.getCredentials(authScope); if (creds != null) { authState.setAuthScheme(new BasicScheme()); authState.setCredentials(creds); } } } }; } }