Skip to content
This repository was archived by the owner on Mar 19, 2024. It is now read-only.

Commit 0e325ca

Browse files
authored
Merge pull request #363 from owncloud/feature/oauth_custom_implementation
[Feature] OAuth2 - OIDC Custom implementation
2 parents c3ffe3d + 9ae7205 commit 0e325ca

File tree

12 files changed

+455
-22
lines changed

12 files changed

+455
-22
lines changed

owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/OwnCloudClient.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,15 @@
4848
import java.io.InputStream;
4949
import java.util.List;
5050

51+
import static com.owncloud.android.lib.common.http.HttpConstants.AUTHORIZATION_HEADER;
5152
import static com.owncloud.android.lib.common.http.HttpConstants.OC_X_REQUEST_ID;
5253

5354
public class OwnCloudClient extends HttpClient {
5455

5556
public static final String WEBDAV_FILES_PATH_4_0 = "/remote.php/dav/files/";
5657
public static final String WEBDAV_PATH_4_0_AND_LATER = "/remote.php/dav";
57-
private static final String WEBDAV_UPLOADS_PATH_4_0 = "/remote.php/dav/uploads/";
5858
public static final String STATUS_PATH = "/status.php";
59-
59+
private static final String WEBDAV_UPLOADS_PATH_4_0 = "/remote.php/dav/uploads/";
6060
private static final int MAX_REDIRECTIONS_COUNT = 3;
6161
private static final int MAX_REPEAT_COUNT_WITH_FRESH_CREDENTIALS = 1;
6262

@@ -104,8 +104,8 @@ public int executeHttpMethod(HttpBaseMethod method) throws Exception {
104104
method.setRequestHeader(HttpConstants.OC_X_REQUEST_ID, requestId);
105105
method.setRequestHeader(HttpConstants.USER_AGENT_HEADER, SingleSessionManager.getUserAgent());
106106
method.setRequestHeader(HttpConstants.ACCEPT_ENCODING_HEADER, HttpConstants.ACCEPT_ENCODING_IDENTITY);
107-
if (mCredentials.getHeaderAuth() != null) {
108-
method.setRequestHeader(HttpConstants.AUTHORIZATION_HEADER, mCredentials.getHeaderAuth());
107+
if (mCredentials.getHeaderAuth() != null && method.getRequestHeader(AUTHORIZATION_HEADER) == null) {
108+
method.setRequestHeader(AUTHORIZATION_HEADER, mCredentials.getHeaderAuth());
109109
}
110110
status = method.execute();
111111

@@ -136,7 +136,7 @@ private int executeRedirectedHttpMethod(HttpBaseMethod method) throws Exception
136136
method.setRequestHeader(HttpConstants.USER_AGENT_HEADER, SingleSessionManager.getUserAgent());
137137
method.setRequestHeader(HttpConstants.ACCEPT_ENCODING_HEADER, HttpConstants.ACCEPT_ENCODING_IDENTITY);
138138
if (mCredentials.getHeaderAuth() != null) {
139-
method.setRequestHeader(HttpConstants.AUTHORIZATION_HEADER, mCredentials.getHeaderAuth());
139+
method.setRequestHeader(AUTHORIZATION_HEADER, mCredentials.getHeaderAuth());
140140
}
141141
status = method.execute();
142142

owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/authentication/OwnCloudCredentialsFactory.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,6 @@
2424

2525
package com.owncloud.android.lib.common.authentication;
2626

27-
import com.owncloud.android.lib.common.OwnCloudClient;
28-
import com.owncloud.android.lib.common.http.HttpClient;
29-
import com.owncloud.android.lib.common.http.HttpConstants;
30-
3127
public class OwnCloudCredentialsFactory {
3228

3329
public static final String CREDENTIAL_CHARSET = "UTF-8";

owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/HttpConstants.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ public class HttpConstants {
5151
public static final String ACCEPT_ENCODING_IDENTITY = "identity";
5252
public static final String OC_FILE_REMOTE_ID = "OC-FileId";
5353

54+
// OAuth
55+
public static final String OAUTH_HEADER_AUTHORIZATION_CODE = "code";
56+
public static final String OAUTH_HEADER_GRANT_TYPE = "grant_type";
57+
public static final String OAUTH_HEADER_REDIRECT_URI = "redirect_uri";
58+
public static final String OAUTH_HEADER_REFRESH_TOKEN = "refresh_token";
59+
5460
/***********************************************************************************************************
5561
************************************************ CONTENT TYPES ********************************************
5662
***********************************************************************************************************/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/* ownCloud Android Library is available under MIT license
2+
*
3+
* @author Abel García de Prada
4+
*
5+
* Copyright (C) 2020 ownCloud GmbH.
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy
8+
* of this software and associated documentation files (the "Software"), to deal
9+
* in the Software without restriction, including without limitation the rights
10+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the Software is
12+
* furnished to do so, subject to the following conditions:
13+
*
14+
* The above copyright notice and this permission notice shall be included in
15+
* all copies or substantial portions of the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21+
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22+
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*
26+
*/
27+
package com.owncloud.android.lib.resources.oauth
28+
29+
import com.owncloud.android.lib.common.OwnCloudClient
30+
import com.owncloud.android.lib.common.http.HttpConstants
31+
import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod
32+
import com.owncloud.android.lib.common.operations.RemoteOperation
33+
import com.owncloud.android.lib.common.operations.RemoteOperationResult
34+
import com.owncloud.android.lib.resources.oauth.responses.OIDCDiscoveryResponse
35+
import com.squareup.moshi.JsonAdapter
36+
import com.squareup.moshi.Moshi
37+
import timber.log.Timber
38+
import java.net.URL
39+
40+
/**
41+
* Get OIDC Discovery
42+
*
43+
* @author Abel García de Prada
44+
*/
45+
class GetOIDCDiscoveryRemoteOperation : RemoteOperation<OIDCDiscoveryResponse>() {
46+
47+
override fun run(client: OwnCloudClient): RemoteOperationResult<OIDCDiscoveryResponse> {
48+
try {
49+
val uriBuilder = client.baseUri.buildUpon().apply {
50+
appendPath(WELL_KNOWN_PATH) // avoid starting "/" in this method
51+
appendPath(OPENID_CONFIGURATION_RESOURCE)
52+
}.build()
53+
54+
val getMethod = GetMethod(URL(uriBuilder.toString())).apply {
55+
addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE)
56+
}
57+
58+
val status = client.executeHttpMethod(getMethod)
59+
60+
val responseBody = getMethod.getResponseBodyAsString()
61+
62+
if (status == HttpConstants.HTTP_OK && responseBody != null) {
63+
Timber.d("Successful response $responseBody")
64+
65+
// Parse the response
66+
val moshi: Moshi = Moshi.Builder().build()
67+
val jsonAdapter: JsonAdapter<OIDCDiscoveryResponse> = moshi.adapter(OIDCDiscoveryResponse::class.java)
68+
val oidcDiscoveryResponse: OIDCDiscoveryResponse? = jsonAdapter.fromJson(responseBody)
69+
Timber.d("Get OIDC Discovery completed and parsed to [$oidcDiscoveryResponse]")
70+
71+
return RemoteOperationResult<OIDCDiscoveryResponse>(RemoteOperationResult.ResultCode.OK).apply {
72+
data = oidcDiscoveryResponse
73+
}
74+
75+
} else {
76+
Timber.e("Failed response while getting OIDC server discovery from the server status code: $status; response message: $responseBody")
77+
78+
return RemoteOperationResult<OIDCDiscoveryResponse>(getMethod)
79+
}
80+
81+
} catch (e: Exception) {
82+
Timber.e(e, "Exception while getting OIDC server discovery")
83+
84+
return RemoteOperationResult<OIDCDiscoveryResponse>(e)
85+
}
86+
}
87+
88+
companion object {
89+
private const val WELL_KNOWN_PATH = ".well-known"
90+
private const val OPENID_CONFIGURATION_RESOURCE = "openid-configuration"
91+
92+
}
93+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/* ownCloud Android Library is available under MIT license
2+
*
3+
* @author Abel García de Prada
4+
*
5+
* Copyright (C) 2020 ownCloud GmbH.
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy
8+
* of this software and associated documentation files (the "Software"), to deal
9+
* in the Software without restriction, including without limitation the rights
10+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the Software is
12+
* furnished to do so, subject to the following conditions:
13+
*
14+
* The above copyright notice and this permission notice shall be included in
15+
* all copies or substantial portions of the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21+
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22+
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*
26+
*/
27+
package com.owncloud.android.lib.resources.oauth
28+
29+
import com.owncloud.android.lib.common.OwnCloudClient
30+
import com.owncloud.android.lib.common.http.HttpConstants.AUTHORIZATION_HEADER
31+
import com.owncloud.android.lib.common.http.HttpConstants.HTTP_OK
32+
import com.owncloud.android.lib.common.http.methods.nonwebdav.PostMethod
33+
import com.owncloud.android.lib.common.operations.RemoteOperation
34+
import com.owncloud.android.lib.common.operations.RemoteOperationResult
35+
import com.owncloud.android.lib.resources.oauth.params.TokenRequestParams
36+
import com.owncloud.android.lib.resources.oauth.responses.TokenResponse
37+
import com.squareup.moshi.JsonAdapter
38+
import com.squareup.moshi.Moshi
39+
import timber.log.Timber
40+
import java.net.URL
41+
42+
/**
43+
* Perform token request
44+
*
45+
* @author Abel García de Prada
46+
*/
47+
class TokenRequestRemoteOperation(
48+
private val tokenRequestParams: TokenRequestParams
49+
) : RemoteOperation<TokenResponse>() {
50+
51+
override fun run(client: OwnCloudClient): RemoteOperationResult<TokenResponse> {
52+
try {
53+
val requestBody = tokenRequestParams.toRequestBody()
54+
55+
val postMethod = PostMethod(URL(tokenRequestParams.tokenEndpoint), requestBody)
56+
57+
postMethod.addRequestHeader(AUTHORIZATION_HEADER, tokenRequestParams.clientAuth)
58+
59+
val status = client.executeHttpMethod(postMethod)
60+
61+
val responseBody = postMethod.getResponseBodyAsString()
62+
63+
if (status == HTTP_OK && responseBody != null) {
64+
Timber.d("Successful response $responseBody")
65+
66+
// Parse the response
67+
val moshi: Moshi = Moshi.Builder().build()
68+
val jsonAdapter: JsonAdapter<TokenResponse> = moshi.adapter(TokenResponse::class.java)
69+
val tokenResponse: TokenResponse? = jsonAdapter.fromJson(responseBody)
70+
Timber.d("Get tokens completed and parsed to $tokenResponse")
71+
72+
return RemoteOperationResult<TokenResponse>(RemoteOperationResult.ResultCode.OK).apply {
73+
data = tokenResponse
74+
}
75+
76+
} else {
77+
Timber.e("Failed response while getting tokens from the server status code: $status; response message: $responseBody")
78+
return RemoteOperationResult<TokenResponse>(postMethod)
79+
}
80+
81+
} catch (e: Exception) {
82+
Timber.e(e, "Exception while getting tokens")
83+
return RemoteOperationResult<TokenResponse>(e)
84+
85+
}
86+
}
87+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/* ownCloud Android Library is available under MIT license
2+
*
3+
* Copyright (C) 2020 ownCloud GmbH.
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19+
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20+
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
package com.owncloud.android.lib.resources.oauth.params
25+
26+
import com.owncloud.android.lib.common.http.HttpConstants
27+
import okhttp3.FormBody
28+
import okhttp3.RequestBody
29+
30+
sealed class TokenRequestParams(
31+
val tokenEndpoint: String,
32+
val clientAuth: String,
33+
val grantType: String
34+
) {
35+
abstract fun toRequestBody(): RequestBody
36+
37+
class Authorization(
38+
tokenEndpoint: String,
39+
clientAuth: String,
40+
grantType: String,
41+
val authorizationCode: String,
42+
val redirectUri: String
43+
) : TokenRequestParams(tokenEndpoint, clientAuth, grantType) {
44+
45+
override fun toRequestBody(): RequestBody {
46+
return FormBody.Builder()
47+
.add(HttpConstants.OAUTH_HEADER_AUTHORIZATION_CODE, authorizationCode)
48+
.add(HttpConstants.OAUTH_HEADER_GRANT_TYPE, grantType)
49+
.add(HttpConstants.OAUTH_HEADER_REDIRECT_URI, redirectUri)
50+
.build()
51+
}
52+
}
53+
54+
class RefreshToken(
55+
tokenEndpoint: String,
56+
clientAuth: String,
57+
grantType: String,
58+
val refreshToken: String? = null
59+
) : TokenRequestParams(tokenEndpoint, clientAuth, grantType) {
60+
61+
override fun toRequestBody(): RequestBody {
62+
return FormBody.Builder().apply {
63+
add(HttpConstants.OAUTH_HEADER_GRANT_TYPE, grantType)
64+
if (!refreshToken.isNullOrBlank()) {
65+
add(HttpConstants.OAUTH_HEADER_REFRESH_TOKEN, refreshToken)
66+
}
67+
}.build()
68+
69+
}
70+
}
71+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/* ownCloud Android Library is available under MIT license
2+
*
3+
* @author Abel García de Prada
4+
*
5+
* Copyright (C) 2020 ownCloud GmbH.
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy
8+
* of this software and associated documentation files (the "Software"), to deal
9+
* in the Software without restriction, including without limitation the rights
10+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the Software is
12+
* furnished to do so, subject to the following conditions:
13+
*
14+
* The above copyright notice and this permission notice shall be included in
15+
* all copies or substantial portions of the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21+
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22+
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*
26+
*/
27+
package com.owncloud.android.lib.resources.oauth.responses
28+
29+
import com.squareup.moshi.JsonClass
30+
31+
@JsonClass(generateAdapter = true)
32+
data class OIDCDiscoveryResponse(
33+
val authorization_endpoint: String,
34+
val check_session_iframe: String,
35+
val end_session_endpoint: String,
36+
val issuer: String,
37+
val registration_endpoint: String,
38+
val response_types_supported: List<String>,
39+
val scopes_supported: List<String>,
40+
val token_endpoint: String,
41+
val token_endpoint_auth_methods_supported: List<String>,
42+
val userinfo_endpoint: String,
43+
)

0 commit comments

Comments
 (0)