diff --git a/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2ClientConfiguration.java b/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2ClientConfiguration.java new file mode 100644 index 00000000..43db97e0 --- /dev/null +++ b/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2ClientConfiguration.java @@ -0,0 +1,66 @@ +/* ownCloud Android Library is available under MIT license + * + * @author David A. Velasco + * Copyright (C) 2017 ownCloud GmbH. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package com.owncloud.android.lib.common.network.authentication.oauth; + +public class OAuth2ClientConfiguration { + + private String mClientId; + + private String mClientSecret; + + private String mRedirectUri; + + public OAuth2ClientConfiguration(String clientId, String clientSecret, String redirectUri) { + mClientId = (clientId == null) ? "" : clientId; + mClientSecret = (clientSecret == null) ? "" : clientSecret; + mRedirectUri = (redirectUri == null) ? "" : redirectUri; + } + + public String getClientId() { + return mClientId; + } + + public void setClientId(String clientId) { + mClientId = clientId; + } + + public String getClientSecret() { + return mClientSecret; + } + + public void setClientSecret(String clientSecret) { + mClientSecret = clientSecret; + } + + public String getRedirectUri() { + return mRedirectUri; + } + + public void setRedirectUri(String redirectUri) { + this.mRedirectUri = redirectUri; + } +} diff --git a/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2Constants.java b/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2Constants.java new file mode 100644 index 00000000..d10c88d6 --- /dev/null +++ b/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2Constants.java @@ -0,0 +1,68 @@ +/* ownCloud Android Library is available under MIT license + * + * @author David A. Velasco + * Copyright (C) 2017 ownCloud GmbH. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package com.owncloud.android.lib.common.network.authentication.oauth; + +/** + * Constant values for OAuth 2 protocol. + * + * Includes required and optional parameter NAMES used in the 'authorization code' grant type. + */ + +public class OAuth2Constants { + + /// Parameters to send to the Authorization Endpoint + public static final String KEY_RESPONSE_TYPE = "response_type"; + public static final String KEY_REDIRECT_URI = "redirect_uri"; + public static final String KEY_CLIENT_ID = "client_id"; + public static final String KEY_SCOPE = "scope"; + public static final String KEY_STATE = "state"; + + /// Additional parameters to send to the Token Endpoint + public static final String KEY_GRANT_TYPE = "grant_type"; + public static final String KEY_CODE = "code"; + + // Used to get the Access Token using Refresh Token + public static final String OAUTH2_REFRESH_TOKEN_GRANT_TYPE = "refresh_token"; + + /// Parameters received in an OK response from the Token Endpoint + public static final String KEY_ACCESS_TOKEN = "access_token"; + public static final String KEY_TOKEN_TYPE = "token_type"; + public static final String KEY_EXPIRES_IN = "expires_in"; + public static final String KEY_REFRESH_TOKEN = "refresh_token"; + + /// Parameters in an ERROR response + public static final String KEY_ERROR = "error"; + public static final String KEY_ERROR_DESCRIPTION = "error_description"; + public static final String KEY_ERROR_URI = "error_uri"; + public static final String VALUE_ERROR_ACCESS_DENIED = "access_denied"; + + /// Extra not standard + public static final String KEY_USER_ID = "user_id"; + + /// Depends on oauth2 grant type + public static final String OAUTH2_RESPONSE_TYPE_CODE = "code"; +} diff --git a/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2GetAccessToken.java b/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2GetAccessToken.java new file mode 100644 index 00000000..f22b3ceb --- /dev/null +++ b/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2GetAccessToken.java @@ -0,0 +1,219 @@ +/* ownCloud Android Library is available under MIT license + * + * @author David A. Velasco + * Copyright (C) 2017 ownCloud GmbH. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package com.owncloud.android.lib.common.network.authentication.oauth; + +import android.net.Uri; + +import com.owncloud.android.lib.common.OwnCloudBasicCredentials; +import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.OwnCloudCredentials; +import com.owncloud.android.lib.common.operations.RemoteOperation; +import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; + +import org.apache.commons.httpclient.NameValuePair; +import org.apache.commons.httpclient.methods.PostMethod; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + + +public class OAuth2GetAccessToken extends RemoteOperation { + + private String mGrantType; + private String mCode; + private String mClientId; + private String mClientSecret; + private String mRedirectUri; + private final String mAccessTokenEndpointPath; + + private Map mResultTokenMap; + + + public OAuth2GetAccessToken( + String grantType, + String code, + String clientId, + String secretId, + String redirectUri, + String accessTokenEndpointPath + ) { + mClientId = clientId; + mClientSecret = secretId; + mRedirectUri = redirectUri; + mGrantType = grantType; + mCode = code; + + mAccessTokenEndpointPath = + accessTokenEndpointPath != null ? + accessTokenEndpointPath : + OwnCloudOAuth2Provider.ACCESS_TOKEN_ENDPOINT_PATH + ; + mResultTokenMap = null; + } + + /* + public Map getResultTokenMap() { + return mResultTokenMap; + } + */ + + @Override + protected RemoteOperationResult run(OwnCloudClient client) { + RemoteOperationResult result = null; + PostMethod postMethod = null; + + try { + NameValuePair[] nameValuePairs = new NameValuePair[4]; + nameValuePairs[0] = new NameValuePair(OAuth2Constants.KEY_GRANT_TYPE, mGrantType); + nameValuePairs[1] = new NameValuePair(OAuth2Constants.KEY_CODE, mCode); + nameValuePairs[2] = new NameValuePair(OAuth2Constants.KEY_REDIRECT_URI, mRedirectUri); + nameValuePairs[3] = new NameValuePair(OAuth2Constants.KEY_CLIENT_ID, mClientId); + + Uri.Builder uriBuilder = client.getBaseUri().buildUpon(); + uriBuilder.appendEncodedPath(mAccessTokenEndpointPath); + + postMethod = new PostMethod(uriBuilder.build().toString()); + postMethod.setRequestBody(nameValuePairs); + + OwnCloudCredentials oauthCredentials = new OwnCloudBasicCredentials( + mClientId, + mClientSecret + ); + OwnCloudCredentials oldCredentials = switchClientCredentials(oauthCredentials); + + client.executeMethod(postMethod); + switchClientCredentials(oldCredentials); + + String response = postMethod.getResponseBodyAsString(); + if (response != null && response.length() > 0) { + JSONObject tokenJson = new JSONObject(response); + parseAccessTokenResult(tokenJson); + if (mResultTokenMap.get(OAuth2Constants.KEY_ERROR) != null || + mResultTokenMap.get(OAuth2Constants.KEY_ACCESS_TOKEN) == null) { + result = new RemoteOperationResult(ResultCode.OAUTH2_ERROR); + + } else { + result = new RemoteOperationResult(true, postMethod); + ArrayList data = new ArrayList<>(); + data.add(mResultTokenMap); + result.setData(data); + } + + } else { + result = new RemoteOperationResult(false, postMethod); + client.exhaustResponse(postMethod.getResponseBodyAsStream()); + } + + } catch (Exception e) { + result = new RemoteOperationResult(e); + + } finally { + if (postMethod != null) + postMethod.releaseConnection(); // let the connection available for other methods + + /* + if (result.isSuccess()) { + Log_OC.i(TAG, "OAuth2 TOKEN REQUEST with auth code " + + mCode + " to " + + client.getWebdavUri() + ": " + result.getLogMessage()); + + } else if (result.getException() != null) { + Log_OC.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + + mCode + " to " + client. + getWebdavUri() + ": " + result.getLogMessage(), result.getException()); + + } else if (result.getCode() == ResultCode.OAUTH2_ERROR) { + Log_OC.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + + mCode + " to " + client. + getWebdavUri() + ": " + ((mResultTokenMap != null) ? mResultTokenMap. + get(OAuth2Constants.KEY_ERROR) : "NULL")); + + } else { + Log_OC.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + + mCode + " to " + client. + getWebdavUri() + ": " + result.getLogMessage()); + } + */ + } + + return result; + } + + private OwnCloudCredentials switchClientCredentials(OwnCloudCredentials newCredentials) { + // work-around for POC with owncloud/oauth2 app, that doesn't allow client + OwnCloudCredentials previousCredentials = getClient().getCredentials(); + getClient().setCredentials(newCredentials); + return previousCredentials; + } + + + private void parseAccessTokenResult (JSONObject tokenJson) throws JSONException { + mResultTokenMap = new HashMap<>(); + + if (tokenJson.has(OAuth2Constants.KEY_ACCESS_TOKEN)) { + mResultTokenMap.put(OAuth2Constants.KEY_ACCESS_TOKEN, tokenJson. + getString(OAuth2Constants.KEY_ACCESS_TOKEN)); + } + if (tokenJson.has(OAuth2Constants.KEY_TOKEN_TYPE)) { + mResultTokenMap.put(OAuth2Constants.KEY_TOKEN_TYPE, tokenJson. + getString(OAuth2Constants.KEY_TOKEN_TYPE)); + } + if (tokenJson.has(OAuth2Constants.KEY_EXPIRES_IN)) { + mResultTokenMap.put(OAuth2Constants.KEY_EXPIRES_IN, tokenJson. + getString(OAuth2Constants.KEY_EXPIRES_IN)); + } + if (tokenJson.has(OAuth2Constants.KEY_REFRESH_TOKEN)) { + mResultTokenMap.put(OAuth2Constants.KEY_REFRESH_TOKEN, tokenJson. + getString(OAuth2Constants.KEY_REFRESH_TOKEN)); + } + if (tokenJson.has(OAuth2Constants.KEY_SCOPE)) { + mResultTokenMap.put(OAuth2Constants.KEY_SCOPE, tokenJson. + getString(OAuth2Constants.KEY_SCOPE)); + } + if (tokenJson.has(OAuth2Constants.KEY_ERROR)) { + mResultTokenMap.put(OAuth2Constants.KEY_ERROR, tokenJson. + getString(OAuth2Constants.KEY_ERROR)); + } + if (tokenJson.has(OAuth2Constants.KEY_ERROR_DESCRIPTION)) { + mResultTokenMap.put(OAuth2Constants.KEY_ERROR_DESCRIPTION, tokenJson. + getString(OAuth2Constants.KEY_ERROR_DESCRIPTION)); + } + if (tokenJson.has(OAuth2Constants.KEY_ERROR_URI)) { + mResultTokenMap.put(OAuth2Constants.KEY_ERROR_URI, tokenJson. + getString(OAuth2Constants.KEY_ERROR_URI)); + } + + if (tokenJson.has(OAuth2Constants.KEY_USER_ID)) { // not standard + mResultTokenMap.put(OAuth2Constants.KEY_USER_ID, tokenJson. + getString(OAuth2Constants.KEY_USER_ID)); + } + } +} diff --git a/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2GrantType.java b/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2GrantType.java new file mode 100644 index 00000000..26c53dba --- /dev/null +++ b/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2GrantType.java @@ -0,0 +1,44 @@ +/* ownCloud Android Library is available under MIT license + * + * @author David A. Velasco + * Copyright (C) 2017 ownCloud GmbH. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package com.owncloud.android.lib.common.network.authentication.oauth; + +public enum OAuth2GrantType { + AUTHORIZATION_CODE("authorization_code"), + IMPLICIT("implicit"), + PASSWORD("password"), + CLIENT_CREDENTIAL("client_credentials"); + + private String mValue; + + OAuth2GrantType(String value) { + mValue = value; + } + + public String getValue() { + return mValue; + } +} diff --git a/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2Provider.java b/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2Provider.java new file mode 100644 index 00000000..b750048c --- /dev/null +++ b/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2Provider.java @@ -0,0 +1,66 @@ +/* ownCloud Android Library is available under MIT license + * + * @author David A. Velasco + * Copyright (C) 2017 ownCloud GmbH. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package com.owncloud.android.lib.common.network.authentication.oauth; + +public interface OAuth2Provider { + + /** + * {@link OAuth2RequestBuilder} implementation for this provider. + * + * @return {@link OAuth2RequestBuilder} implementation. + */ + OAuth2RequestBuilder getOperationBuilder(); + + + /** + * Set configuration of the client that will use this {@link OAuth2Provider} + * @param oAuth2ClientConfiguration Configuration of the client that will use this {@link OAuth2Provider} + */ + void setClientConfiguration(OAuth2ClientConfiguration oAuth2ClientConfiguration); + + /** + * Configuration of the client that is using this {@link OAuth2Provider} + * return Configuration of the client that is usinng this {@link OAuth2Provider} + */ + OAuth2ClientConfiguration getClientConfiguration(); + + + /** + * Set base URI to authorization server. + * + * @param authorizationServerUri Set base URL to authorization server. + */ + void setAuthorizationServerUri(String authorizationServerUri); + + /** + * base URI to authorization server. + * + * @return Base URL to authorization server. + */ + String getAuthorizationServerUri(); + +} diff --git a/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2ProvidersRegistry.java b/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2ProvidersRegistry.java new file mode 100644 index 00000000..b827215f --- /dev/null +++ b/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2ProvidersRegistry.java @@ -0,0 +1,122 @@ +/* ownCloud Android Library is available under MIT license + * + * @author David A. Velasco + * Copyright (C) 2017 ownCloud GmbH. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package com.owncloud.android.lib.common.network.authentication.oauth; + + +import java.util.HashMap; +import java.util.Map; + +public class OAuth2ProvidersRegistry { + + private Map mProviders = new HashMap<>(); + + private OAuth2Provider mDefaultProvider = null; + + private OAuth2ProvidersRegistry () { + } + + /** + * See https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom + */ + private static class LazyHolder { + private static final OAuth2ProvidersRegistry INSTANCE = new OAuth2ProvidersRegistry(); + } + + /** + * Singleton accesor. + * + * @return Singleton isntance of {@link OAuth2ProvidersRegistry} + */ + public static OAuth2ProvidersRegistry getInstance() { + return LazyHolder.INSTANCE; + } + + /** + * Register an {@link OAuth2Provider} with the name passed as parameter. + * + * @param name Name to bind 'oAuthProvider' in the registry. + * @param oAuth2Provider An {@link OAuth2Provider} instance to keep in the registry. + * @throws IllegalArgumentException if 'name' or 'oAuthProvider' are null. + */ + public void registerProvider(String name, OAuth2Provider oAuth2Provider) { + if (name == null) { + throw new IllegalArgumentException("Name must not be NULL"); + } + if (oAuth2Provider == null) { + throw new IllegalArgumentException("oAuth2Provider must not be NULL"); + } + + mProviders.put(name, oAuth2Provider); + if (mProviders.size() == 1) { + mDefaultProvider = oAuth2Provider; + } + } + + public OAuth2Provider unregisterProvider(String name) { + OAuth2Provider unregisteredProvider = mProviders.remove(name); + if (mProviders.size() == 0) { + mDefaultProvider = null; + } else if (unregisteredProvider != null && unregisteredProvider == mDefaultProvider) { + mDefaultProvider = mProviders.values().iterator().next(); + } + return unregisteredProvider; + } + + /** + * Get default {@link OAuth2Provider}. + * + * @return Default provider, or NULL if there is no provider. + */ + public OAuth2Provider getProvider() { + return mDefaultProvider; + } + + /** + * Get {@link OAuth2Provider} registered with the name passed as parameter. + * + * @param name Name used to register the desired {@link OAuth2Provider} + * @return {@link OAuth2Provider} registered with the name 'name' + */ + public OAuth2Provider getProvider(String name) { + return mProviders.get(name); + } + + /** + * Sets the {@link OAuth2Provider} registered with the name passed as parameter as the default provider + * + * @param name Name used to register the {@link OAuth2Provider} to set as default. + * @return {@link OAuth2Provider} set as default, or NULL if no provider was registered with 'name'. + */ + public OAuth2Provider setDefaultProvider(String name) { + OAuth2Provider toDefault = mProviders.get(name); + if (toDefault != null) { + mDefaultProvider = toDefault; + } + return toDefault; + } + +} diff --git a/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2QueryParser.java b/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2QueryParser.java new file mode 100644 index 00000000..98b89fe8 --- /dev/null +++ b/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2QueryParser.java @@ -0,0 +1,73 @@ +/* ownCloud Android Library is available under MIT license + * + * @author David A. Velasco + * Copyright (C) 2017 ownCloud GmbH. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package com.owncloud.android.lib.common.network.authentication.oauth; + +import com.owncloud.android.lib.common.utils.Log_OC; + +import java.util.HashMap; +import java.util.Map; + + +public class OAuth2QueryParser { + + private static final String TAG = OAuth2QueryParser.class.getName(); + + private Map mOAuth2ParsedAuthorizationResponse; + + public OAuth2QueryParser() { + mOAuth2ParsedAuthorizationResponse = new HashMap<>(); + } + + public Map parse(String query) { + mOAuth2ParsedAuthorizationResponse.clear(); + + String[] pairs = query.split("&"); + int i = 0; + String key = ""; + String value; + while (pairs.length > i) { + int j = 0; + String[] part = pairs[i].split("="); + while (part.length > j) { + String p = part[j]; + if (j == 0) { + key = p; + } else if (j == 1) { + value = p; + mOAuth2ParsedAuthorizationResponse.put(key, value); + } + + Log_OC.v(TAG, "[" + i + "," + j + "] = " + p); + j++; + } + i++; + } + + return mOAuth2ParsedAuthorizationResponse; + } + +} diff --git a/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2RequestBuilder.java b/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2RequestBuilder.java new file mode 100644 index 00000000..9d3008e0 --- /dev/null +++ b/src/com/owncloud/android/lib/common/network/authentication/oauth/OAuth2RequestBuilder.java @@ -0,0 +1,47 @@ +/* ownCloud Android Library is available under MIT license + * + * @author David A. Velasco + * Copyright (C) 2017 ownCloud GmbH. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package com.owncloud.android.lib.common.network.authentication.oauth; + +import com.owncloud.android.lib.common.operations.RemoteOperation; + +public interface OAuth2RequestBuilder { + + enum OAuthRequest { + GET_AUTHORIZATION_CODE, CREATE_ACCESS_TOKEN + } + + void setRequest(OAuthRequest operation); + + void setGrantType(OAuth2GrantType grantType); + + void setAuthorizationCode(String code); + + RemoteOperation buildOperation(); + + String buildUri(); + +} diff --git a/src/com/owncloud/android/lib/common/network/authentication/oauth/OwnCloudOAuth2Provider.java b/src/com/owncloud/android/lib/common/network/authentication/oauth/OwnCloudOAuth2Provider.java new file mode 100644 index 00000000..75ab493b --- /dev/null +++ b/src/com/owncloud/android/lib/common/network/authentication/oauth/OwnCloudOAuth2Provider.java @@ -0,0 +1,94 @@ +/* ownCloud Android Library is available under MIT license + * + * @author David A. Velasco + * Copyright (C) 2017 ownCloud GmbH. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package com.owncloud.android.lib.common.network.authentication.oauth; + +import com.owncloud.android.lib.common.utils.Log_OC; + +public class OwnCloudOAuth2Provider implements OAuth2Provider { + + public static final String NAME = OAuth2Provider.class.getName(); + + public static final String ACCESS_TOKEN_ENDPOINT_PATH = "index.php/apps/oauth2/api/v1/token"; + private static final String AUTHORIZATION_CODE_ENDPOINT_PATH = "index.php/apps/oauth2/authorize"; + + private String mAuthorizationServerUrl = ""; + private String mAccessTokenEndpointPath = ACCESS_TOKEN_ENDPOINT_PATH; + private String mAuthorizationCodeEndpointPath = AUTHORIZATION_CODE_ENDPOINT_PATH; + + private OAuth2ClientConfiguration mClientConfiguration; + + @Override + public OAuth2RequestBuilder getOperationBuilder() { + return new OwnCloudOAuth2RequestBuilder(this); + } + + @Override + public void setClientConfiguration(OAuth2ClientConfiguration oAuth2ClientConfiguration) { + mClientConfiguration = oAuth2ClientConfiguration; + } + + @Override + public OAuth2ClientConfiguration getClientConfiguration() { + return mClientConfiguration; + } + + @Override + public void setAuthorizationServerUri(String authorizationServerUri) { + mAuthorizationServerUrl = authorizationServerUri; + } + + @Override + public String getAuthorizationServerUri() { + return mAuthorizationServerUrl; + } + + public String getAccessTokenEndpointPath() { + return mAccessTokenEndpointPath; + } + + public void setAccessTokenEndpointPath(String accessTokenEndpointPath) { + if (accessTokenEndpointPath == null || accessTokenEndpointPath.length() <= 0) { + Log_OC.w(NAME, "Setting invalid access token endpoint path, going on with default"); + mAccessTokenEndpointPath = ACCESS_TOKEN_ENDPOINT_PATH; + } else { + mAccessTokenEndpointPath = accessTokenEndpointPath; + } + } + + public String getAuthorizationCodeEndpointPath() { + return mAuthorizationCodeEndpointPath; + } + + public void setAuthorizationCodeEndpointPath(String authorizationCodeEndpointPath) { + if (authorizationCodeEndpointPath == null || authorizationCodeEndpointPath.length() <= 0) { + Log_OC.w(NAME, "Setting invalid authorization code endpoint path, going on with default"); + mAuthorizationCodeEndpointPath = AUTHORIZATION_CODE_ENDPOINT_PATH; + } else { + mAuthorizationCodeEndpointPath = authorizationCodeEndpointPath; + } + } +} diff --git a/src/com/owncloud/android/lib/common/network/authentication/oauth/OwnCloudOAuth2RequestBuilder.java b/src/com/owncloud/android/lib/common/network/authentication/oauth/OwnCloudOAuth2RequestBuilder.java new file mode 100644 index 00000000..83549879 --- /dev/null +++ b/src/com/owncloud/android/lib/common/network/authentication/oauth/OwnCloudOAuth2RequestBuilder.java @@ -0,0 +1,139 @@ +/* ownCloud Android Library is available under MIT license + * + * @author David A. Velasco + * Copyright (C) 2017 ownCloud GmbH. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +package com.owncloud.android.lib.common.network.authentication.oauth; + +import android.net.Uri; + +import com.owncloud.android.lib.common.operations.RemoteOperation; + +public class OwnCloudOAuth2RequestBuilder implements OAuth2RequestBuilder { + + private OwnCloudOAuth2Provider mOAuth2Provider; + + private OAuthRequest mRequest; + private OAuth2GrantType mGrantType = OAuth2GrantType.AUTHORIZATION_CODE; + private String mCode; + + public OwnCloudOAuth2RequestBuilder(OwnCloudOAuth2Provider ownCloudOAuth2Provider) { + mOAuth2Provider = ownCloudOAuth2Provider; + } + + @Override + public void setRequest(OAuthRequest request) { + mRequest = request; + } + + @Override + public void setGrantType(OAuth2GrantType grantType) { + mGrantType = grantType; + } + + @Override + public void setAuthorizationCode(String code) { + mCode = code; + } + + @Override + public RemoteOperation buildOperation() { + if (OAuth2GrantType.AUTHORIZATION_CODE != mGrantType) { + throw new UnsupportedOperationException( + "Unsupported grant type. Only " + + OAuth2GrantType.AUTHORIZATION_CODE.getValue() + " is supported" + ); + } + switch(mRequest) { + case CREATE_ACCESS_TOKEN: + OAuth2ClientConfiguration clientConfiguration = mOAuth2Provider.getClientConfiguration(); + return new OAuth2GetAccessToken( + mGrantType.getValue(), + mCode, + clientConfiguration.getClientId(), + clientConfiguration.getClientSecret(), + clientConfiguration.getRedirectUri(), + mOAuth2Provider.getAccessTokenEndpointPath() + ); + default: + throw new UnsupportedOperationException( + "Unsupported request" + ); + } + } + + @Override + public String buildUri() { + if (OAuth2GrantType.AUTHORIZATION_CODE != mGrantType) { + throw new UnsupportedOperationException( + "Unsupported grant type. Only " + + OAuth2GrantType.AUTHORIZATION_CODE.getValue() + " is supported by this provider" + ); + } + OAuth2ClientConfiguration clientConfiguration = mOAuth2Provider.getClientConfiguration(); + Uri uri; + Uri.Builder uriBuilder; + switch(mRequest) { + case GET_AUTHORIZATION_CODE: + uri = Uri.parse(mOAuth2Provider.getAuthorizationServerUri()); + uriBuilder = uri.buildUpon(); + uriBuilder.appendEncodedPath(mOAuth2Provider.getAuthorizationCodeEndpointPath()); + uriBuilder.appendQueryParameter( + OAuth2Constants.KEY_RESPONSE_TYPE, OAuth2Constants.OAUTH2_RESPONSE_TYPE_CODE + ); + uriBuilder.appendQueryParameter( + OAuth2Constants.KEY_REDIRECT_URI, clientConfiguration.getRedirectUri() + ); + uriBuilder.appendQueryParameter( + OAuth2Constants.KEY_CLIENT_ID, clientConfiguration.getClientId() + ); + + uri = uriBuilder.build(); + return uri.toString(); + + case CREATE_ACCESS_TOKEN: + uri = Uri.parse(mOAuth2Provider.getAuthorizationServerUri()); + uriBuilder = uri.buildUpon(); + uriBuilder.appendEncodedPath(mOAuth2Provider.getAccessTokenEndpointPath()); + uriBuilder.appendQueryParameter( + OAuth2Constants.KEY_RESPONSE_TYPE, OAuth2Constants.OAUTH2_RESPONSE_TYPE_CODE + ); + uriBuilder.appendQueryParameter( + OAuth2Constants.KEY_REDIRECT_URI, clientConfiguration.getRedirectUri() + ); + uriBuilder.appendQueryParameter( + OAuth2Constants.KEY_CLIENT_ID, clientConfiguration.getClientId() + ); + + uri = uriBuilder.build(); + return uri.toString(); + + default: + throw new UnsupportedOperationException( + "Unsupported request" + ); + } + } + +}