mirror of
				https://github.com/owncloud/android-library.git
				synced 2025-10-30 01:48:14 +00:00 
			
		
		
		
	Merge pull request #300 from owncloud/new_arch/oauth_app_auth
Implement OAuth2 with AppAuth
This commit is contained in:
		
						commit
						8f9bed2d9f
					
				
							
								
								
									
										3
									
								
								gradle.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								gradle.properties
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| android.enableJetifier=true | ||||
| android.useAndroidX=true | ||||
| org.gradle.jvmargs=-Xmx1536M | ||||
| @ -8,6 +8,7 @@ dependencies { | ||||
|     implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion" | ||||
|     api 'com.gitlab.ownclouders:dav4android:oc_support_1.0.1' | ||||
|     api 'com.github.hannesa2:Logcat:1.6.0' | ||||
|     api 'net.openid:appauth:0.7.1' | ||||
| } | ||||
| 
 | ||||
| allOpen { | ||||
| @ -24,6 +25,10 @@ android { | ||||
| 
 | ||||
|         versionCode = 10000401 | ||||
|         versionName = "1.0.4.1" | ||||
| 
 | ||||
|         // This is pretty ugly but manifest placeholders don't seem to work very well when using different modules | ||||
|         // See https://github.com/openid/AppAuth-Android/issues/325 | ||||
|         manifestPlaceholders = [appAuthRedirectScheme: ''] | ||||
|     } | ||||
| 
 | ||||
|     lintOptions { | ||||
|  | ||||
| @ -334,7 +334,6 @@ public class OwnCloudClient extends HttpClient { | ||||
|             if (invalidated) { | ||||
|                 if (getCredentials().authTokenCanBeRefreshed() && | ||||
|                         repeatCounter < MAX_REPEAT_COUNT_WITH_FRESH_CREDENTIALS) { | ||||
| 
 | ||||
|                     try { | ||||
|                         mAccount.loadCredentials(getContext()); | ||||
|                         // if mAccount.getCredentials().length() == 0 --> refresh failed | ||||
| @ -342,7 +341,9 @@ public class OwnCloudClient extends HttpClient { | ||||
|                         credentialsWereRefreshed = true; | ||||
| 
 | ||||
|                     } catch (AccountsException | IOException e) { | ||||
|                         Timber.e(e, "Error while trying to refresh auth token for %s", mAccount.getSavedAccount().name); | ||||
|                         Timber.e(e, "Error while trying to refresh auth token for %s", | ||||
|                                 mAccount.getSavedAccount().name | ||||
|                         ); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|  | ||||
| @ -37,8 +37,7 @@ public class OwnCloudClientFactory { | ||||
|      * @param context Android context where the OwnCloudClient is being created. | ||||
|      * @return A OwnCloudClient object ready to be used | ||||
|      */ | ||||
|     public static OwnCloudClient createOwnCloudClient(Uri uri, Context context, | ||||
|                                                       boolean followRedirects) { | ||||
|     public static OwnCloudClient createOwnCloudClient(Uri uri, Context context, boolean followRedirects) { | ||||
|         OwnCloudClient client = new OwnCloudClient(uri); | ||||
| 
 | ||||
|         client.setFollowRedirects(followRedirects); | ||||
|  | ||||
| @ -315,9 +315,19 @@ public class AccountUtils { | ||||
|          */ | ||||
|         public static final String KEY_DISPLAY_NAME = "oc_display_name"; | ||||
| 
 | ||||
|         /** | ||||
|          * OAuth2 user id | ||||
|          **/ | ||||
|         public static final String KEY_USER_ID = "user_id"; | ||||
| 
 | ||||
|         /** | ||||
|          * OAuth2 refresh token | ||||
|          **/ | ||||
|         public static final String KEY_OAUTH2_REFRESH_TOKEN = "oc_oauth2_refresh_token"; | ||||
| 
 | ||||
|         /** | ||||
|          * OAuth2 scope | ||||
|          */ | ||||
|         public static final String KEY_OAUTH2_SCOPE = "oc_oauth2_scope"; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,95 +0,0 @@ | ||||
| /* ownCloud Android Library is available under MIT license | ||||
|  *   Copyright (C) 2019 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.authentication.oauth; | ||||
| 
 | ||||
| /** | ||||
|  * @author David A. Velasco | ||||
|  * @author Christian Schabesberger | ||||
|  */ | ||||
| public class BearerCredentials { | ||||
| 
 | ||||
|     public static final int HASH_SEED = 17; | ||||
|     public static final int HASH_OFFSET = 37; | ||||
| 
 | ||||
|     private String mAccessToken; | ||||
| 
 | ||||
|     /** | ||||
|      * The constructor with the bearer token | ||||
|      * | ||||
|      * @param token The bearer token | ||||
|      */ | ||||
|     public BearerCredentials(String token) { | ||||
|         mAccessToken = (token == null) ? "" : token; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns the access token | ||||
|      * | ||||
|      * @return The access token | ||||
|      */ | ||||
|     public String getAccessToken() { | ||||
|         return mAccessToken; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get this object string. | ||||
|      * | ||||
|      * @return The access token | ||||
|      */ | ||||
|     public String toString() { | ||||
|         return mAccessToken; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Does a hash of the access token. | ||||
|      * | ||||
|      * @return The hash code of the access token | ||||
|      */ | ||||
|     public int hashCode() { | ||||
|         return HASH_SEED * HASH_OFFSET + mAccessToken.hashCode(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * These credentials are assumed equal if accessToken is the same. | ||||
|      * | ||||
|      * @param o The other object to compare with. | ||||
|      * @return 'True' if the object is equivalent. | ||||
|      */ | ||||
|     public boolean equals(Object o) { | ||||
|         if (o == null) { | ||||
|             return false; | ||||
|         } | ||||
|         if (this == o) { | ||||
|             return true; | ||||
|         } | ||||
|         if (this.getClass().equals(o.getClass())) { | ||||
|             BearerCredentials that = (BearerCredentials) o; | ||||
|             if (mAccessToken.equals(that.mAccessToken)) { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| @ -1,66 +0,0 @@ | ||||
| /* 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.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 == null) ? "" : clientId; | ||||
|     } | ||||
| 
 | ||||
|     public String getClientSecret() { | ||||
|         return mClientSecret; | ||||
|     } | ||||
| 
 | ||||
|     public void setClientSecret(String clientSecret) { | ||||
|         mClientSecret = (clientSecret == null) ? "" : clientSecret; | ||||
|     } | ||||
| 
 | ||||
|     public String getRedirectUri() { | ||||
|         return mRedirectUri; | ||||
|     } | ||||
| 
 | ||||
|     public void setRedirectUri(String redirectUri) { | ||||
|         this.mRedirectUri = (redirectUri == null) ? "" : redirectUri; | ||||
|     } | ||||
| } | ||||
| @ -1,68 +0,0 @@ | ||||
| /* 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.authentication.oauth; | ||||
| 
 | ||||
| /** | ||||
|  * Constant values for OAuth 2 protocol. | ||||
|  * <p> | ||||
|  * 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"; | ||||
| } | ||||
| @ -1,141 +0,0 @@ | ||||
| /* ownCloud Android Library is available under MIT license | ||||
|  * | ||||
|  *   @author David A. Velasco | ||||
|  *   @author Christian Schabesberger | ||||
|  *   Copyright (C) 2019 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.authentication.oauth; | ||||
| 
 | ||||
| import android.net.Uri; | ||||
| 
 | ||||
| import com.owncloud.android.lib.common.OwnCloudClient; | ||||
| import com.owncloud.android.lib.common.authentication.OwnCloudBasicCredentials; | ||||
| import com.owncloud.android.lib.common.authentication.OwnCloudCredentials; | ||||
| import com.owncloud.android.lib.common.http.methods.nonwebdav.PostMethod; | ||||
| 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 okhttp3.MultipartBody; | ||||
| import okhttp3.RequestBody; | ||||
| import org.json.JSONObject; | ||||
| 
 | ||||
| import java.net.URL; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| public class OAuth2GetAccessTokenOperation extends RemoteOperation<Map<String, String>> { | ||||
| 
 | ||||
|     private final String mAccessTokenEndpointPath; | ||||
|     private final OAuth2ResponseParser mResponseParser; | ||||
|     private String mGrantType; | ||||
|     private String mCode; | ||||
|     private String mClientId; | ||||
|     private String mClientSecret; | ||||
|     private String mRedirectUri; | ||||
| 
 | ||||
|     public OAuth2GetAccessTokenOperation( | ||||
|             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 | ||||
|         ; | ||||
| 
 | ||||
|         mResponseParser = new OAuth2ResponseParser(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected RemoteOperationResult run(OwnCloudClient client) { | ||||
|         RemoteOperationResult<Map<String, String>> result = null; | ||||
| 
 | ||||
|         try { | ||||
| 
 | ||||
|             final RequestBody requestBody = new MultipartBody.Builder() | ||||
|                     .setType(MultipartBody.FORM) | ||||
|                     .addFormDataPart(OAuth2Constants.KEY_GRANT_TYPE, mGrantType) | ||||
|                     .addFormDataPart(OAuth2Constants.KEY_CODE, mCode) | ||||
|                     .addFormDataPart(OAuth2Constants.KEY_REDIRECT_URI, mRedirectUri) | ||||
|                     .addFormDataPart(OAuth2Constants.KEY_CLIENT_ID, mClientId) | ||||
|                     .build(); | ||||
| 
 | ||||
|             Uri.Builder uriBuilder = client.getBaseUri().buildUpon(); | ||||
|             uriBuilder.appendEncodedPath(mAccessTokenEndpointPath); | ||||
| 
 | ||||
|             final PostMethod postMethod = new PostMethod(new URL( | ||||
|                     client.getBaseUri().buildUpon() | ||||
|                             .appendEncodedPath(mAccessTokenEndpointPath) | ||||
|                             .build() | ||||
|                             .toString())); | ||||
| 
 | ||||
|             postMethod.setRequestBody(requestBody); | ||||
| 
 | ||||
|             OwnCloudCredentials oauthCredentials = | ||||
|                     new OwnCloudBasicCredentials(mClientId, mClientSecret); | ||||
|             OwnCloudCredentials oldCredentials = switchClientCredentials(oauthCredentials); | ||||
|             client.executeHttpMethod(postMethod); | ||||
|             switchClientCredentials(oldCredentials); | ||||
| 
 | ||||
|             String response = postMethod.getResponseBodyAsString(); | ||||
|             if (response != null && response.length() > 0) { | ||||
|                 JSONObject tokenJson = new JSONObject(response); | ||||
|                 Map<String, String> accessTokenResult = | ||||
|                         mResponseParser.parseAccessTokenResult(tokenJson); | ||||
|                 if (accessTokenResult.get(OAuth2Constants.KEY_ERROR) != null || | ||||
|                         accessTokenResult.get(OAuth2Constants.KEY_ACCESS_TOKEN) == null) { | ||||
|                     result = new RemoteOperationResult<>(ResultCode.OAUTH2_ERROR); | ||||
| 
 | ||||
|                 } else { | ||||
|                     result = new RemoteOperationResult<>(ResultCode.OK); | ||||
|                     result.setData(accessTokenResult); | ||||
|                 } | ||||
| 
 | ||||
|             } else { | ||||
|                 result = new RemoteOperationResult<>(ResultCode.OK); | ||||
|                 client.exhaustResponse(postMethod.getResponseBodyAsStream()); | ||||
|             } | ||||
| 
 | ||||
|         } catch (Exception e) { | ||||
|             result = new RemoteOperationResult<>(e); | ||||
| 
 | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     private OwnCloudCredentials switchClientCredentials(OwnCloudCredentials newCredentials) { | ||||
|         OwnCloudCredentials previousCredentials = getClient().getCredentials(); | ||||
|         getClient().setCredentials(newCredentials); | ||||
|         return previousCredentials; | ||||
|     } | ||||
| } | ||||
| @ -1,46 +0,0 @@ | ||||
| /* 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.authentication.oauth; | ||||
| 
 | ||||
| public enum OAuth2GrantType { | ||||
|     AUTHORIZATION_CODE("authorization_code"), | ||||
|     IMPLICIT("implicit"), | ||||
|     PASSWORD("password"), | ||||
|     CLIENT_CREDENTIAL("client_credentials"), | ||||
|     REFRESH_TOKEN("refresh_token")  // not a grant type conceptually, but used as such to refresh access tokens | ||||
|     ; | ||||
| 
 | ||||
|     private String mValue; | ||||
| 
 | ||||
|     OAuth2GrantType(String value) { | ||||
|         mValue = value; | ||||
|     } | ||||
| 
 | ||||
|     public String getValue() { | ||||
|         return mValue; | ||||
|     } | ||||
| } | ||||
| @ -1,65 +0,0 @@ | ||||
| /* 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.authentication.oauth; | ||||
| 
 | ||||
| public interface OAuth2Provider { | ||||
| 
 | ||||
|     /** | ||||
|      * {@link OAuth2RequestBuilder} implementation for this provider. | ||||
|      * | ||||
|      * @return {@link OAuth2RequestBuilder} implementation. | ||||
|      */ | ||||
|     OAuth2RequestBuilder getOperationBuilder(); | ||||
| 
 | ||||
|     /** | ||||
|      * Configuration of the client that is using this {@link OAuth2Provider} | ||||
|      * return                   Configuration of the client that is usinng this {@link OAuth2Provider} | ||||
|      */ | ||||
|     OAuth2ClientConfiguration getClientConfiguration(); | ||||
| 
 | ||||
|     /** | ||||
|      * 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); | ||||
| 
 | ||||
|     /** | ||||
|      * base URI to authorization server. | ||||
|      * | ||||
|      * @return Base URL to authorization server. | ||||
|      */ | ||||
|     String getAuthorizationServerUri(); | ||||
| 
 | ||||
|     /** | ||||
|      * Set base URI to authorization server. | ||||
|      * | ||||
|      * @param authorizationServerUri Set base URL to authorization server. | ||||
|      */ | ||||
|     void setAuthorizationServerUri(String authorizationServerUri); | ||||
| 
 | ||||
| } | ||||
| @ -1,121 +0,0 @@ | ||||
| /* 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.authentication.oauth; | ||||
| 
 | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| public class OAuth2ProvidersRegistry { | ||||
| 
 | ||||
|     private Map<String, OAuth2Provider> mProviders = new HashMap<>(); | ||||
| 
 | ||||
|     private OAuth2Provider mDefaultProvider = null; | ||||
| 
 | ||||
|     private 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; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * See https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom | ||||
|      */ | ||||
|     private static class LazyHolder { | ||||
|         private static final OAuth2ProvidersRegistry INSTANCE = new OAuth2ProvidersRegistry(); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,72 +0,0 @@ | ||||
| /* 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.authentication.oauth; | ||||
| 
 | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| public class OAuth2QueryParser { | ||||
| 
 | ||||
|     private Map<String, String> mOAuth2ParsedAuthorizationResponse; | ||||
| 
 | ||||
|     public OAuth2QueryParser() { | ||||
|         mOAuth2ParsedAuthorizationResponse = new HashMap<>(); | ||||
|     } | ||||
| 
 | ||||
|     public Map<String, String> parse(String query) { | ||||
|         mOAuth2ParsedAuthorizationResponse.clear(); | ||||
| 
 | ||||
|         if (query != null) { | ||||
|             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); | ||||
|                     } | ||||
| 
 | ||||
|                     Timber.v("[" + i + "," + j + "] = " + p); | ||||
|                     j++; | ||||
|                 } | ||||
|                 i++; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return mOAuth2ParsedAuthorizationResponse; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,126 +0,0 @@ | ||||
| /** | ||||
|  * ownCloud Android client application | ||||
|  * | ||||
|  * @author David González Verdugo | ||||
|  * @author Christian Schabesberger | ||||
|  * <p> | ||||
|  * Copyright (C) 2019 ownCloud GmbH. | ||||
|  * <p> | ||||
|  * This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2, | ||||
|  * as published by the Free Software Foundation. | ||||
|  * <p> | ||||
|  * 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. | ||||
|  * <p> | ||||
|  * 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.owncloud.android.lib.common.authentication.oauth; | ||||
| 
 | ||||
| import android.net.Uri; | ||||
| 
 | ||||
| import com.owncloud.android.lib.common.OwnCloudClient; | ||||
| import com.owncloud.android.lib.common.authentication.OwnCloudBasicCredentials; | ||||
| import com.owncloud.android.lib.common.authentication.OwnCloudCredentials; | ||||
| import com.owncloud.android.lib.common.http.methods.nonwebdav.PostMethod; | ||||
| 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 okhttp3.MultipartBody; | ||||
| import okhttp3.RequestBody; | ||||
| import org.json.JSONObject; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
| import java.net.URL; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| public class OAuth2RefreshAccessTokenOperation extends RemoteOperation<Map<String, String>> { | ||||
| 
 | ||||
|     private final String mAccessTokenEndpointPath; | ||||
|     private final OAuth2ResponseParser mResponseParser; | ||||
|     private String mClientId; | ||||
|     private String mClientSecret; | ||||
|     private String mRefreshToken; | ||||
| 
 | ||||
|     public OAuth2RefreshAccessTokenOperation( | ||||
|             String clientId, | ||||
|             String secretId, | ||||
|             String refreshToken, | ||||
|             String accessTokenEndpointPath | ||||
|     ) { | ||||
| 
 | ||||
|         mClientId = clientId; | ||||
|         mClientSecret = secretId; | ||||
|         mRefreshToken = refreshToken; | ||||
| 
 | ||||
|         mAccessTokenEndpointPath = | ||||
|                 accessTokenEndpointPath != null ? | ||||
|                         accessTokenEndpointPath : | ||||
|                         OwnCloudOAuth2Provider.ACCESS_TOKEN_ENDPOINT_PATH | ||||
|         ; | ||||
| 
 | ||||
|         mResponseParser = new OAuth2ResponseParser(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected RemoteOperationResult<Map<String, String>> run(OwnCloudClient client) { | ||||
| 
 | ||||
|         try { | ||||
|             final RequestBody requestBody = new MultipartBody.Builder() | ||||
|                     .setType(MultipartBody.FORM) | ||||
|                     .addFormDataPart(OAuth2Constants.KEY_GRANT_TYPE, | ||||
|                             OAuth2GrantType.REFRESH_TOKEN.getValue()) | ||||
|                     .addFormDataPart(OAuth2Constants.KEY_CLIENT_ID, mClientId) | ||||
|                     .addFormDataPart(OAuth2Constants.KEY_REFRESH_TOKEN, mRefreshToken) | ||||
|                     .build(); | ||||
| 
 | ||||
|             Uri.Builder uriBuilder = client.getBaseUri().buildUpon(); | ||||
|             uriBuilder.appendEncodedPath(mAccessTokenEndpointPath); | ||||
| 
 | ||||
|             final PostMethod postMethod = new PostMethod(new URL( | ||||
|                     client.getBaseUri().buildUpon() | ||||
|                             .appendEncodedPath(mAccessTokenEndpointPath) | ||||
|                             .build() | ||||
|                             .toString())); | ||||
|             postMethod.setRequestBody(requestBody); | ||||
| 
 | ||||
|             final OwnCloudCredentials oauthCredentials = new OwnCloudBasicCredentials(mClientId, mClientSecret); | ||||
| 
 | ||||
|             final OwnCloudCredentials oldCredentials = switchClientCredentials(oauthCredentials); | ||||
|             client.executeHttpMethod(postMethod); | ||||
|             switchClientCredentials(oldCredentials); | ||||
| 
 | ||||
|             final String responseData = postMethod.getResponseBodyAsString(); | ||||
|             Timber.d("OAUTH2: raw response from POST TOKEN: %s", responseData); | ||||
| 
 | ||||
|             if (responseData != null && responseData.length() > 0) { | ||||
|                 final JSONObject tokenJson = new JSONObject(responseData); | ||||
| 
 | ||||
|                 final Map<String, String> accessTokenResult = | ||||
|                         mResponseParser.parseAccessTokenResult(tokenJson); | ||||
| 
 | ||||
|                 final RemoteOperationResult<Map<String, String>> result = new RemoteOperationResult<>(ResultCode.OK); | ||||
|                 result.setData(accessTokenResult); | ||||
|                 return (accessTokenResult.get(OAuth2Constants.KEY_ERROR) != null || | ||||
|                         accessTokenResult.get(OAuth2Constants.KEY_ACCESS_TOKEN) == null) | ||||
|                         ? new RemoteOperationResult<>(ResultCode.OAUTH2_ERROR) | ||||
|                         : result; | ||||
|             } else { | ||||
|                 return new RemoteOperationResult<>(postMethod); | ||||
|             } | ||||
| 
 | ||||
|         } catch (Exception e) { | ||||
|             return new RemoteOperationResult<>(e); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private OwnCloudCredentials switchClientCredentials(OwnCloudCredentials newCredentials) { | ||||
|         OwnCloudCredentials previousCredentials = getClient().getCredentials(); | ||||
|         getClient().setCredentials(newCredentials); | ||||
|         return previousCredentials; | ||||
|     } | ||||
| } | ||||
| @ -1,48 +0,0 @@ | ||||
| /* 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.authentication.oauth; | ||||
| 
 | ||||
| import com.owncloud.android.lib.common.operations.RemoteOperation; | ||||
| 
 | ||||
| public interface OAuth2RequestBuilder { | ||||
| 
 | ||||
|     void setRequest(OAuthRequest operation); | ||||
| 
 | ||||
|     void setGrantType(OAuth2GrantType grantType); | ||||
| 
 | ||||
|     void setAuthorizationCode(String code); | ||||
| 
 | ||||
|     void setRefreshToken(String refreshToken); | ||||
| 
 | ||||
|     RemoteOperation buildOperation(); | ||||
| 
 | ||||
|     String buildUri(); | ||||
| 
 | ||||
|     enum OAuthRequest { | ||||
|         GET_AUTHORIZATION_CODE, CREATE_ACCESS_TOKEN, REFRESH_ACCESS_TOKEN | ||||
|     } | ||||
| } | ||||
| @ -1,75 +0,0 @@ | ||||
| /** | ||||
|  * ownCloud Android client application | ||||
|  * | ||||
|  * @author David A. Velasco | ||||
|  * <p> | ||||
|  * Copyright (C) 2017 ownCloud GmbH. | ||||
|  * <p> | ||||
|  * This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2, | ||||
|  * as published by the Free Software Foundation. | ||||
|  * <p> | ||||
|  * 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. | ||||
|  * <p> | ||||
|  * 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.owncloud.android.lib.common.authentication.oauth; | ||||
| 
 | ||||
| import org.json.JSONException; | ||||
| import org.json.JSONObject; | ||||
| 
 | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| class OAuth2ResponseParser { | ||||
| 
 | ||||
|     Map<String, String> parseAccessTokenResult(JSONObject tokenJson) throws JSONException { | ||||
|         Map<String, String> resultTokenMap = new HashMap<>(); | ||||
| 
 | ||||
|         if (tokenJson.has(OAuth2Constants.KEY_ACCESS_TOKEN)) { | ||||
|             resultTokenMap.put(OAuth2Constants.KEY_ACCESS_TOKEN, tokenJson. | ||||
|                     getString(OAuth2Constants.KEY_ACCESS_TOKEN)); | ||||
|         } | ||||
|         if (tokenJson.has(OAuth2Constants.KEY_TOKEN_TYPE)) { | ||||
|             resultTokenMap.put(OAuth2Constants.KEY_TOKEN_TYPE, tokenJson. | ||||
|                     getString(OAuth2Constants.KEY_TOKEN_TYPE)); | ||||
|         } | ||||
|         if (tokenJson.has(OAuth2Constants.KEY_EXPIRES_IN)) { | ||||
|             resultTokenMap.put(OAuth2Constants.KEY_EXPIRES_IN, tokenJson. | ||||
|                     getString(OAuth2Constants.KEY_EXPIRES_IN)); | ||||
|         } | ||||
|         if (tokenJson.has(OAuth2Constants.KEY_REFRESH_TOKEN)) { | ||||
|             resultTokenMap.put(OAuth2Constants.KEY_REFRESH_TOKEN, tokenJson. | ||||
|                     getString(OAuth2Constants.KEY_REFRESH_TOKEN)); | ||||
|         } | ||||
|         if (tokenJson.has(OAuth2Constants.KEY_SCOPE)) { | ||||
|             resultTokenMap.put(OAuth2Constants.KEY_SCOPE, tokenJson. | ||||
|                     getString(OAuth2Constants.KEY_SCOPE)); | ||||
|         } | ||||
|         if (tokenJson.has(OAuth2Constants.KEY_ERROR)) { | ||||
|             resultTokenMap.put(OAuth2Constants.KEY_ERROR, tokenJson. | ||||
|                     getString(OAuth2Constants.KEY_ERROR)); | ||||
|         } | ||||
|         if (tokenJson.has(OAuth2Constants.KEY_ERROR_DESCRIPTION)) { | ||||
|             resultTokenMap.put(OAuth2Constants.KEY_ERROR_DESCRIPTION, tokenJson. | ||||
|                     getString(OAuth2Constants.KEY_ERROR_DESCRIPTION)); | ||||
|         } | ||||
|         if (tokenJson.has(OAuth2Constants.KEY_ERROR_URI)) { | ||||
|             resultTokenMap.put(OAuth2Constants.KEY_ERROR_URI, tokenJson. | ||||
|                     getString(OAuth2Constants.KEY_ERROR_URI)); | ||||
|         } | ||||
| 
 | ||||
|         if (tokenJson.has(OAuth2Constants.KEY_USER_ID)) {   // not standard | ||||
|             resultTokenMap.put(OAuth2Constants.KEY_USER_ID, tokenJson. | ||||
|                     getString(OAuth2Constants.KEY_USER_ID)); | ||||
|         } | ||||
| 
 | ||||
|         return resultTokenMap; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,73 @@ | ||||
| package com.owncloud.android.lib.common.authentication.oauth | ||||
| 
 | ||||
| import android.content.Context | ||||
| import android.net.Uri | ||||
| import com.owncloud.android.lib.common.network.AdvancedX509TrustManager | ||||
| import com.owncloud.android.lib.common.network.NetworkUtils | ||||
| import net.openid.appauth.connectivity.ConnectionBuilder | ||||
| import timber.log.Timber | ||||
| import java.io.IOException | ||||
| import java.net.HttpURLConnection | ||||
| import java.net.URL | ||||
| import java.security.NoSuchAlgorithmException | ||||
| import java.util.Objects | ||||
| import java.util.concurrent.TimeUnit | ||||
| import javax.net.ssl.HostnameVerifier | ||||
| import javax.net.ssl.HttpsURLConnection | ||||
| import javax.net.ssl.SSLContext | ||||
| import javax.net.ssl.TrustManager | ||||
| import javax.net.ssl.X509TrustManager | ||||
| 
 | ||||
| /** | ||||
|  * Based on [net.openid.appauth.connectivity.DefaultConnectionBuilder] but permitting http connections in addition | ||||
|  * to https connections | ||||
|  */ | ||||
| class OAuthConnectionBuilder(val context: Context) : ConnectionBuilder { | ||||
|     /** | ||||
|      * The singleton instance of the default connection builder. | ||||
|      */ | ||||
|     private val CONNECTION_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(15).toInt() | ||||
|     private val READ_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10).toInt() | ||||
|     private val HTTPS_SCHEME = "https" | ||||
| 
 | ||||
|     @Throws(IOException::class) | ||||
|     override fun openConnection(uri: Uri): HttpURLConnection { | ||||
|         val conn: HttpURLConnection | ||||
| 
 | ||||
|         if (Objects.equals(uri.scheme, HTTPS_SCHEME)) { | ||||
|             conn = URL(uri.toString()).openConnection() as HttpsURLConnection | ||||
|             try { | ||||
|                 val trustManager: X509TrustManager = AdvancedX509TrustManager( | ||||
|                     NetworkUtils.getKnownServersStore(context) | ||||
|                 ) | ||||
|                 val sslContext: SSLContext | ||||
|                 sslContext = try { | ||||
|                     SSLContext.getInstance("TLSv1.2") | ||||
|                 } catch (tlsv12Exception: NoSuchAlgorithmException) { | ||||
|                     try { | ||||
|                         Timber.w("TLSv1.2 is not supported in this device; falling through TLSv1.1") | ||||
|                         SSLContext.getInstance("TLSv1.1") | ||||
|                     } catch (tlsv11Exception: NoSuchAlgorithmException) { | ||||
|                         Timber.w("TLSv1.1 is not supported in this device; falling through TLSv1.0") | ||||
|                         SSLContext.getInstance("TLSv1") | ||||
|                         // should be available in any device; see reference of supported protocols in | ||||
|                         // http://developer.android.com/reference/javax/net/ssl/SSLSocket.html | ||||
|                     } | ||||
|                 } | ||||
|                 sslContext.init(null, arrayOf<TrustManager>(trustManager), null) | ||||
|                 conn.hostnameVerifier = HostnameVerifier { _, _ -> true } // Do not verify the host for now | ||||
|                 conn.sslSocketFactory = sslContext.socketFactory | ||||
|             } catch (e: Exception) { | ||||
|                 Timber.e(e, "Could not setup SSL system") | ||||
|             } | ||||
|         } else { | ||||
|             conn = URL(uri.toString()).openConnection() as HttpURLConnection | ||||
|         } | ||||
| 
 | ||||
|         return conn.apply { | ||||
|             connectTimeout = CONNECTION_TIMEOUT_MS | ||||
|             readTimeout = READ_TIMEOUT_MS | ||||
|             instanceFollowRedirects = false | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -1,94 +0,0 @@ | ||||
| /* 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.authentication.oauth; | ||||
| 
 | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
| 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 OAuth2ClientConfiguration getClientConfiguration() { | ||||
|         return mClientConfiguration; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void setClientConfiguration(OAuth2ClientConfiguration oAuth2ClientConfiguration) { | ||||
|         mClientConfiguration = oAuth2ClientConfiguration; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public String getAuthorizationServerUri() { | ||||
|         return mAuthorizationServerUrl; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void setAuthorizationServerUri(String authorizationServerUri) { | ||||
|         mAuthorizationServerUrl = authorizationServerUri; | ||||
|     } | ||||
| 
 | ||||
|     public String getAccessTokenEndpointPath() { | ||||
|         return mAccessTokenEndpointPath; | ||||
|     } | ||||
| 
 | ||||
|     public void setAccessTokenEndpointPath(String accessTokenEndpointPath) { | ||||
|         if (accessTokenEndpointPath == null || accessTokenEndpointPath.length() <= 0) { | ||||
|             Timber.w("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) { | ||||
|             Timber.w("Setting invalid authorization code endpoint path, going on with default"); | ||||
|             mAuthorizationCodeEndpointPath = AUTHORIZATION_CODE_ENDPOINT_PATH; | ||||
|         } else { | ||||
|             mAuthorizationCodeEndpointPath = authorizationCodeEndpointPath; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -1,155 +0,0 @@ | ||||
| /* 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.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; | ||||
|     private String mRefreshToken; | ||||
| 
 | ||||
|     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 void setRefreshToken(String refreshToken) { | ||||
|         mRefreshToken = refreshToken; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public RemoteOperation buildOperation() { | ||||
|         if (mGrantType != OAuth2GrantType.AUTHORIZATION_CODE && | ||||
|                 mGrantType != OAuth2GrantType.REFRESH_TOKEN) { | ||||
|             throw new UnsupportedOperationException( | ||||
|                     "Unsupported grant type. Only " + | ||||
|                             OAuth2GrantType.AUTHORIZATION_CODE.getValue() + " and " + | ||||
|                             OAuth2GrantType.REFRESH_TOKEN + " are supported" | ||||
|             ); | ||||
|         } | ||||
|         OAuth2ClientConfiguration clientConfiguration = mOAuth2Provider.getClientConfiguration(); | ||||
| 
 | ||||
|         switch (mRequest) { | ||||
|             case CREATE_ACCESS_TOKEN: | ||||
|                 return new OAuth2GetAccessTokenOperation( | ||||
|                         mGrantType.getValue(), | ||||
|                         mCode, | ||||
|                         clientConfiguration.getClientId(), | ||||
|                         clientConfiguration.getClientSecret(), | ||||
|                         clientConfiguration.getRedirectUri(), | ||||
|                         mOAuth2Provider.getAccessTokenEndpointPath() | ||||
|                 ); | ||||
| 
 | ||||
|             case REFRESH_ACCESS_TOKEN: | ||||
|                 return new OAuth2RefreshAccessTokenOperation( | ||||
|                         clientConfiguration.getClientId(), | ||||
|                         clientConfiguration.getClientSecret(), | ||||
|                         mRefreshToken, | ||||
|                         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" | ||||
|                 ); | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user