1
0
mirror of https://github.com/owncloud/android-library.git synced 2025-06-07 16:06:08 +00:00

Grant that requests send through the same OwnCloudClient using SAML SSO Authentication keep cookies

This commit is contained in:
David A. Velasco 2014-05-29 17:49:45 +02:00
parent 1cb224cba1
commit 3eedb86091

View File

@ -30,6 +30,7 @@ import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpClient;
@ -57,28 +58,43 @@ import android.net.Uri;
import android.util.Log; import android.util.Log;
public class OwnCloudClient extends HttpClient { public class OwnCloudClient extends HttpClient {
private static final String TAG = OwnCloudClient.class.getSimpleName();
public static final String USER_AGENT = "Android-ownCloud";
private static final int MAX_REDIRECTIONS_COUNT = 3; private static final int MAX_REDIRECTIONS_COUNT = 3;
private static final String PARAM_SINGLE_COOKIE_HEADER = "http.protocol.single-cookie-header";
private static final boolean PARAM_SINGLE_COOKIE_HEADER_VALUE = true;
private static byte[] sExhaustBuffer = new byte[1024];
private static int sIntanceCounter = 0;
private boolean mFollowRedirects = true;
private Credentials mCredentials = null;
private String mSsoSessionCookie = null;
private int mInstanceNumber = 0;
private Uri mUri; private Uri mUri;
private Uri mWebdavUri; private Uri mWebdavUri;
private Credentials mCredentials;
private boolean mFollowRedirects;
private String mSsoSessionCookie;
final private static String TAG = OwnCloudClient.class.getSimpleName();
public static final String USER_AGENT = "Android-ownCloud";
static private byte[] sExhaustBuffer = new byte[1024];
/** /**
* Constructor * Constructor
*/ */
public OwnCloudClient(HttpConnectionManager connectionMgr) { public OwnCloudClient(HttpConnectionManager connectionMgr) {
super(connectionMgr); super(connectionMgr);
Log.d(TAG, "Creating OwnCloudClient");
mInstanceNumber = sIntanceCounter++;
Log.d(TAG + " #" + mInstanceNumber, "Creating OwnCloudClient");
getParams().setParameter(HttpMethodParams.USER_AGENT, USER_AGENT); getParams().setParameter(HttpMethodParams.USER_AGENT, USER_AGENT);
getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); getParams().setParameter(
mFollowRedirects = true; CoreProtocolPNames.PROTOCOL_VERSION,
mSsoSessionCookie = null; HttpVersion.HTTP_1_1);
getParams().setCookiePolicy(
CookiePolicy.BROWSER_COMPATIBILITY); // to keep sessions
getParams().setParameter(
PARAM_SINGLE_COOKIE_HEADER, // to avoid problems with some web servers
PARAM_SINGLE_COOKIE_HEADER_VALUE);
} }
public void setBearerCredentials(String accessToken) { public void setBearerCredentials(String accessToken) {
@ -88,6 +104,7 @@ public class OwnCloudClient extends HttpClient {
authPrefs.add(BearerAuthScheme.AUTH_POLICY); authPrefs.add(BearerAuthScheme.AUTH_POLICY);
getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs); getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);
getParams().setAuthenticationPreemptive(true);
mCredentials = new BearerCredentials(accessToken); mCredentials = new BearerCredentials(accessToken);
getState().setCredentials(AuthScope.ANY, mCredentials); getState().setCredentials(AuthScope.ANY, mCredentials);
mSsoSessionCookie = null; mSsoSessionCookie = null;
@ -102,14 +119,38 @@ public class OwnCloudClient extends HttpClient {
mCredentials = new UsernamePasswordCredentials(username, password); mCredentials = new UsernamePasswordCredentials(username, password);
getState().setCredentials(AuthScope.ANY, mCredentials); getState().setCredentials(AuthScope.ANY, mCredentials);
mSsoSessionCookie = null; mSsoSessionCookie = null;
getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
} }
public void setSsoSessionCookie(String accessToken) { public void setSsoSessionCookie(String accessToken) {
Log.d(TAG + " #" + mInstanceNumber, "Setting session cookie: " + accessToken);
Log.e(TAG + " #" + mInstanceNumber, "BASE URL: " + mUri);
Log.e(TAG + " #" + mInstanceNumber, "WebDAV URL: " + mWebdavUri);
getParams().setAuthenticationPreemptive(false); getParams().setAuthenticationPreemptive(false);
getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
mSsoSessionCookie = accessToken; mSsoSessionCookie = accessToken;
mCredentials = null; mCredentials = null;
Uri serverUri = (mUri != null)? mUri : mWebdavUri;
// TODO refactoring the mess of URIs
String[] cookies = mSsoSessionCookie.split(";");
if (cookies.length > 0) {
//Cookie[] cookies = new Cookie[cookiesStr.length];
for (int i=0; i<cookies.length; i++) {
Cookie cookie = new Cookie();
int equalPos = cookies[i].indexOf('=');
cookie.setName(cookies[i].substring(0, equalPos));
//Log.d(TAG, "Set name for cookie: " + cookies[i].substring(0, equalPos));
cookie.setValue(cookies[i].substring(equalPos + 1));
//Log.d(TAG, "Set value for cookie: " + cookies[i].substring(equalPos + 1));
cookie.setDomain(serverUri.getHost()); // VERY IMPORTANT
//Log.d(TAG, "Set domain for cookie: " + serverUri.getHost());
cookie.setPath(serverUri.getPath()); // VERY IMPORTANT
Log.d(TAG, "Set path for cookie: " + serverUri.getPath());
getState().addCookie(cookie);
}
}
} }
@ -125,7 +166,8 @@ public class OwnCloudClient extends HttpClient {
HeadMethod head = new HeadMethod(mWebdavUri.toString() + WebdavUtils.encodePath(path)); HeadMethod head = new HeadMethod(mWebdavUri.toString() + WebdavUtils.encodePath(path));
try { try {
int status = executeMethod(head); int status = executeMethod(head);
Log.d(TAG, "HEAD to " + path + " finished with HTTP status " + status + ((status != HttpStatus.SC_OK)?"(FAIL)":"")); Log.d(TAG, "HEAD to " + path + " finished with HTTP status " + status +
((status != HttpStatus.SC_OK)?"(FAIL)":""));
exhaustResponse(head.getResponseBodyAsStream()); exhaustResponse(head.getResponseBodyAsStream());
return (status == HttpStatus.SC_OK); return (status == HttpStatus.SC_OK);
@ -141,19 +183,21 @@ public class OwnCloudClient extends HttpClient {
* *
* Sets the socket and connection timeouts only for the method received. * Sets the socket and connection timeouts only for the method received.
* *
* The timeouts are both in milliseconds; 0 means 'infinite'; < 0 means 'do not change the default' * The timeouts are both in milliseconds; 0 means 'infinite';
* < 0 means 'do not change the default'
* *
* @param method HTTP method request. * @param method HTTP method request.
* @param readTimeout Timeout to set for data reception * @param readTimeout Timeout to set for data reception
* @param conntionTimout Timeout to set for connection establishment * @param conntionTimout Timeout to set for connection establishment
*/ */
public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout) throws HttpException, IOException { public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout)
throws HttpException, IOException {
int oldSoTimeout = getParams().getSoTimeout(); int oldSoTimeout = getParams().getSoTimeout();
int oldConnectionTimeout = getHttpConnectionManager().getParams().getConnectionTimeout(); int oldConnectionTimeout = getHttpConnectionManager().getParams().getConnectionTimeout();
try { try {
if (readTimeout >= 0) { if (readTimeout >= 0) {
method.getParams().setSoTimeout(readTimeout); // this should be enough... method.getParams().setSoTimeout(readTimeout); // this should be enough...
getParams().setSoTimeout(readTimeout); // ... but this looks like necessary for HTTPS getParams().setSoTimeout(readTimeout); // ... but HTTPS needs this
} }
if (connectionTimeout >= 0) { if (connectionTimeout >= 0) {
getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout); getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout);
@ -168,43 +212,71 @@ public class OwnCloudClient extends HttpClient {
@Override @Override
public int executeMethod(HttpMethod method) throws IOException, HttpException { public int executeMethod(HttpMethod method) throws IOException, HttpException {
boolean customRedirectionNeeded = false; try { // just to log
try { boolean customRedirectionNeeded = false;
method.setFollowRedirects(mFollowRedirects); try {
} catch (Exception e) { method.setFollowRedirects(mFollowRedirects);
//if (mFollowRedirects) Log_OC.d(TAG, "setFollowRedirects failed for " + method.getName() + " method, custom redirection will be used if needed"); } catch (Exception e) {
customRedirectionNeeded = mFollowRedirects; /*
if (mFollowRedirects)
Log_OC.d(TAG, "setFollowRedirects failed for " + method.getName()
+ " method, custom redirection will be used if needed");
*/
customRedirectionNeeded = mFollowRedirects;
}
Log.d(TAG + " #" + mInstanceNumber, "REQUEST " +
method.getName() + " " + method.getPath());
logCookiesAtRequest(method.getRequestHeaders(), "before");
logCookiesAtState("before");
int status = super.executeMethod(method);
if (customRedirectionNeeded) {
status = patchRedirection(status, method);
}
logCookiesAtRequest(method.getRequestHeaders(), "after");
logCookiesAtState("after");
logSetCookiesAtResponse(method.getResponseHeaders());
return status;
} catch (IOException e) {
Log.d(TAG + " #" + mInstanceNumber, "Exception occured", e);
throw e;
} }
if (mSsoSessionCookie != null && mSsoSessionCookie.length() > 0) { }
method.addRequestHeader("Cookie", mSsoSessionCookie);
} private int patchRedirection(int status, HttpMethod method) throws HttpException, IOException {
int status = super.executeMethod(method);
int redirectionsCount = 0; int redirectionsCount = 0;
while (customRedirectionNeeded && while (redirectionsCount < MAX_REDIRECTIONS_COUNT &&
redirectionsCount < MAX_REDIRECTIONS_COUNT &&
( status == HttpStatus.SC_MOVED_PERMANENTLY || ( status == HttpStatus.SC_MOVED_PERMANENTLY ||
status == HttpStatus.SC_MOVED_TEMPORARILY || status == HttpStatus.SC_MOVED_TEMPORARILY ||
status == HttpStatus.SC_TEMPORARY_REDIRECT) status == HttpStatus.SC_TEMPORARY_REDIRECT)
) { ) {
Header location = method.getResponseHeader("Location"); Header location = method.getResponseHeader("Location");
if (location == null) {
location = method.getResponseHeader("location");
}
if (location != null) { if (location != null) {
Log.d(TAG, "Location to redirect: " + location.getValue()); Log.d(TAG + " #" + mInstanceNumber,
"Location to redirect: " + location.getValue());
method.setURI(new URI(location.getValue(), true)); method.setURI(new URI(location.getValue(), true));
status = super.executeMethod(method); status = super.executeMethod(method);
redirectionsCount++; redirectionsCount++;
} else { } else {
Log.d(TAG, "No location to redirect!"); Log.d(TAG + " #" + mInstanceNumber, "No location to redirect!");
status = HttpStatus.SC_NOT_FOUND; status = HttpStatus.SC_NOT_FOUND;
} }
} }
return status; return status;
} }
/**
/**
* Exhausts a not interesting HTTP response. Encouraged by HttpClient documentation. * Exhausts a not interesting HTTP response. Encouraged by HttpClient documentation.
* *
* @param responseBodyAsStream InputStream with the HTTP response to exhaust. * @param responseBodyAsStream InputStream with the HTTP response to exhaust.
@ -216,13 +288,15 @@ public class OwnCloudClient extends HttpClient {
responseBodyAsStream.close(); responseBodyAsStream.close();
} catch (IOException io) { } catch (IOException io) {
Log.e(TAG, "Unexpected exception while exhausting not interesting HTTP response; will be IGNORED", io); Log.e(TAG, "Unexpected exception while exhausting not interesting HTTP response;" +
" will be IGNORED", io);
} }
} }
} }
/** /**
* Sets the connection and wait-for-data timeouts to be applied by default to the methods performed by this client. * Sets the connection and wait-for-data timeouts to be applied by default to the methods
* performed by this client.
*/ */
public void setDefaultTimeouts(int defaultDataTimeout, int defaultConnectionTimeout) { public void setDefaultTimeouts(int defaultDataTimeout, int defaultConnectionTimeout) {
getParams().setSoTimeout(defaultDataTimeout); getParams().setSoTimeout(defaultDataTimeout);
@ -230,7 +304,8 @@ public class OwnCloudClient extends HttpClient {
} }
/** /**
* Sets the Webdav URI for the helper methods that receive paths as parameters, instead of full URLs * Sets the Webdav URI for the helper methods that receive paths as parameters,
* instead of full URLs
* @param uri * @param uri
*/ */
public void setWebdavUri(Uri uri) { public void setWebdavUri(Uri uri) {
@ -242,7 +317,9 @@ public class OwnCloudClient extends HttpClient {
} }
/** /**
* Sets the base URI for the helper methods that receive paths as parameters, instead of full URLs * Sets the base URI for the helper methods that receive paths as parameters,
* instead of full URLs
*
* @param uri * @param uri
*/ */
public void setBaseUri(Uri uri) { public void setBaseUri(Uri uri) {
@ -265,4 +342,51 @@ public class OwnCloudClient extends HttpClient {
mFollowRedirects = followRedirects; mFollowRedirects = followRedirects;
} }
private void logCookiesAtRequest(Header[] headers, String when) {
int counter = 0;
for (int i=0; i<headers.length; i++) {
if (headers[i].getName().toLowerCase().equals("cookie")) {
Log.d(TAG + " #" + mInstanceNumber,
"Cookies at request (" + when + ") (" + counter++ + "): " +
headers[i].getValue());
}
}
if (counter == 0) {
Log.d(TAG + " #" + mInstanceNumber, "No cookie at request before");
}
}
private void logCookiesAtState(String string) {
Cookie[] cookies = getState().getCookies();
if (cookies.length == 0) {
Log.d(TAG + " #" + mInstanceNumber, "No cookie at STATE before");
} else {
Log.d(TAG + " #" + mInstanceNumber, "Cookies at STATE (before)");
for (int i=0; i<cookies.length; i++) {
Log.d(TAG + " #" + mInstanceNumber, " (" + i + "):" +
"\n name: " + cookies[i].getName() +
"\n value: " + cookies[i].getValue() +
"\n domain: " + cookies[i].getDomain() +
"\n path: " + cookies[i].getPath()
);
}
}
}
private void logSetCookiesAtResponse(Header[] headers) {
int counter = 0;
for (int i=0; i<headers.length; i++) {
if (headers[i].getName().toLowerCase().equals("set-cookie")) {
Log.d(TAG + " #" + mInstanceNumber,
"Set-Cookie (" + counter++ + "): " + headers[i].getValue());
}
}
if (counter == 0) {
Log.d(TAG + " #" + mInstanceNumber, "No set-cookie");
}
}
} }