OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.chromoting; | 5 package org.chromium.chromoting; |
6 | 6 |
7 import android.app.Activity; | 7 import android.app.Activity; |
8 import android.content.ActivityNotFoundException; | 8 import android.content.ActivityNotFoundException; |
9 import android.content.ComponentName; | 9 import android.content.ComponentName; |
10 import android.content.Intent; | 10 import android.content.Intent; |
11 import android.content.pm.PackageManager; | 11 import android.content.pm.PackageManager; |
12 import android.net.Uri; | 12 import android.net.Uri; |
| 13 import android.text.TextUtils; |
13 import android.util.Base64; | 14 import android.util.Base64; |
14 import android.util.Log; | 15 import android.util.Log; |
15 | 16 |
16 import java.security.SecureRandom; | 17 import java.security.SecureRandom; |
| 18 import java.util.ArrayList; |
17 import java.util.HashMap; | 19 import java.util.HashMap; |
18 | 20 |
19 /** | 21 /** |
20 * This class is responsible for fetching a third party token from the user usin
g the OAuth2 | 22 * This class is responsible for fetching a third party token from the user usin
g the OAuth2 |
21 * implicit flow. It pops up a third party login page located at |tokenurl|. I
t relies on the | 23 * implicit flow. It pops up a third party login page located at |tokenurl|. I
t relies on the |
22 * |ThirdPartyTokenFetcher$OAuthRedirectActivity| to intercept the access token
from the redirect at | 24 * |ThirdPartyTokenFetcher$OAuthRedirectActivity| to intercept the access token
from the redirect at |
23 * |REDIRECT_URI_SCHEME|://|REDIRECT_URI_HOST| upon successful login. | 25 * |REDIRECT_URI_SCHEME|://|REDIRECT_URI_HOST| upon successful login. |
24 */ | 26 */ |
25 public class ThirdPartyTokenFetcher { | 27 public class ThirdPartyTokenFetcher { |
26 /** Callback for receiving the token. */ | 28 /** Callback for receiving the token. */ |
(...skipping 17 matching lines...) Expand all Loading... |
44 private Activity mContext; | 46 private Activity mContext; |
45 | 47 |
46 /** | 48 /** |
47 * An opaque value used by the client to maintain state between the request
and callback. The | 49 * An opaque value used by the client to maintain state between the request
and callback. The |
48 * authorization server includes this value when redirecting the user-agent
back to the client. | 50 * authorization server includes this value when redirecting the user-agent
back to the client. |
49 * The parameter is used for preventing cross-site request forgery. See | 51 * The parameter is used for preventing cross-site request forgery. See |
50 * http://tools.ietf.org/html/rfc6749#section-10.12. | 52 * http://tools.ietf.org/html/rfc6749#section-10.12. |
51 */ | 53 */ |
52 private final String mState; | 54 private final String mState; |
53 | 55 |
54 /** URL of the third party login page. */ | 56 private final Callback mCallback; |
55 private final String mTokenUrl; | |
56 | 57 |
57 /** The client identifier. See http://tools.ietf.org/html/rfc6749#section-2.
2. */ | 58 /** The list of TokenUrls allowed by the domain. */ |
58 private final String mClientId; | 59 private final ArrayList<String> mTokenUrlPatterns; |
59 | |
60 /** The scope of access request. See http://tools.ietf.org/html/rfc6749#sect
ion-3.3. */ | |
61 private final String mScope; | |
62 | |
63 private final Callback mCallback; | |
64 | 60 |
65 private final String mRedirectUriScheme; | 61 private final String mRedirectUriScheme; |
66 | 62 |
67 private final String mRedirectUri; | 63 private final String mRedirectUri; |
68 | 64 |
69 public ThirdPartyTokenFetcher(Activity context, | 65 public ThirdPartyTokenFetcher(Activity context, |
70 String tokenUrl, | 66 ArrayList<String> tokenUrlPatterns, |
71 String clientId, | |
72 String scope, | |
73 Callback callback) { | 67 Callback callback) { |
74 this.mContext = context; | 68 this.mContext = context; |
75 this.mTokenUrl = tokenUrl; | |
76 this.mClientId = clientId; | |
77 this.mState = generateXsrfToken(); | 69 this.mState = generateXsrfToken(); |
78 this.mScope = scope; | |
79 this.mCallback = callback; | 70 this.mCallback = callback; |
| 71 this.mTokenUrlPatterns = tokenUrlPatterns; |
80 | 72 |
81 this.mRedirectUriScheme = context.getApplicationContext().getPackageName
(); | 73 this.mRedirectUriScheme = context.getApplicationContext().getPackageName
(); |
82 this.mRedirectUri = mRedirectUriScheme + "://" + REDIRECT_URI_HOST; | 74 this.mRedirectUri = mRedirectUriScheme + "://" + REDIRECT_URI_HOST; |
83 } | 75 } |
84 | 76 |
85 public void fetchToken() { | 77 /** |
86 Uri.Builder uriBuilder = Uri.parse(mTokenUrl).buildUpon(); | 78 * @param tokenUrl URL of the third party login page. |
87 uriBuilder.appendQueryParameter("redirect_uri", this.mRedirectUri); | 79 * @param clientId The client identifier. See http://tools.ietf.org/html/rfc
6749#section-2.2. |
88 uriBuilder.appendQueryParameter("scope", mScope); | 80 * @param scope The scope of access request. See http://tools.ietf.org/html/
rfc6749#section-3.3. |
89 uriBuilder.appendQueryParameter("client_id", mClientId); | 81 */ |
90 uriBuilder.appendQueryParameter("state", mState); | 82 public void fetchToken(String tokenUrl, String clientId, String scope) { |
91 uriBuilder.appendQueryParameter("response_type", RESPONSE_TYPE); | 83 if (!isValidTokenUrl(tokenUrl)) { |
| 84 failFetchToken( |
| 85 "Token URL does not match the domain\'s allowed URL patterns
." + |
| 86 " URL: " + tokenUrl + |
| 87 ", patterns: " + TextUtils.join(",", this.mTokenUrlPatterns)
); |
| 88 return; |
| 89 } |
92 | 90 |
93 Uri uri = uriBuilder.build(); | 91 Uri uri = buildRequestUri(tokenUrl, clientId, scope); |
94 Intent intent = new Intent(Intent.ACTION_VIEW, uri); | 92 Intent intent = new Intent(Intent.ACTION_VIEW, uri); |
95 Log.i("ThirdPartyAuth", "fetchToken() url:" + uri); | 93 Log.i("ThirdPartyAuth", "fetchToken() url:" + uri); |
96 OAuthRedirectActivity.setEnabled(mContext, true); | 94 OAuthRedirectActivity.setEnabled(mContext, true); |
97 | 95 |
98 try { | 96 try { |
99 mContext.startActivity(intent); | 97 mContext.startActivity(intent); |
100 } catch (ActivityNotFoundException e) { | 98 } catch (ActivityNotFoundException e) { |
101 failFetchToken("No browser is installed to open the third party auth
entication page."); | 99 failFetchToken("No browser is installed to open the third party auth
entication page."); |
102 } | 100 } |
103 } | 101 } |
104 | 102 |
| 103 private Uri buildRequestUri(String tokenUrl, String clientId, String scope)
{ |
| 104 Uri.Builder uriBuilder = Uri.parse(tokenUrl).buildUpon(); |
| 105 uriBuilder.appendQueryParameter("redirect_uri", this.mRedirectUri); |
| 106 uriBuilder.appendQueryParameter("scope", scope); |
| 107 uriBuilder.appendQueryParameter("client_id", clientId); |
| 108 uriBuilder.appendQueryParameter("state", mState); |
| 109 uriBuilder.appendQueryParameter("response_type", RESPONSE_TYPE); |
| 110 |
| 111 return uriBuilder.build(); |
| 112 } |
| 113 |
| 114 /** Verifies the host-supplied URL matches the domain's allowed URL patterns
. */ |
| 115 private boolean isValidTokenUrl(String tokenUrl) { |
| 116 for (String pattern : mTokenUrlPatterns) { |
| 117 if (tokenUrl.matches(pattern)) { |
| 118 return true; |
| 119 } |
| 120 } |
| 121 return false; |
| 122 } |
| 123 |
105 private boolean isValidIntent(Intent intent) { | 124 private boolean isValidIntent(Intent intent) { |
106 assert intent != null; | 125 assert intent != null; |
107 | 126 |
108 String action = intent.getAction(); | 127 String action = intent.getAction(); |
109 | 128 |
110 Uri data = intent.getData(); | 129 Uri data = intent.getData(); |
111 if (data != null) { | 130 if (data != null) { |
112 return Intent.ACTION_VIEW.equals(action) && | 131 return Intent.ACTION_VIEW.equals(action) && |
113 this.mRedirectUriScheme.equals(data.getScheme()) && | 132 this.mRedirectUriScheme.equals(data.getScheme()) && |
114 REDIRECT_URI_HOST.equals(data.getHost()); | 133 REDIRECT_URI_HOST.equals(data.getHost()); |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
216 ComponentName component = new ComponentName( | 235 ComponentName component = new ComponentName( |
217 context.getApplicationContext(), | 236 context.getApplicationContext(), |
218 ThirdPartyTokenFetcher.OAuthRedirectActivity.class); | 237 ThirdPartyTokenFetcher.OAuthRedirectActivity.class); |
219 context.getPackageManager().setComponentEnabledSetting( | 238 context.getPackageManager().setComponentEnabledSetting( |
220 component, | 239 component, |
221 enabledState, | 240 enabledState, |
222 PackageManager.DONT_KILL_APP); | 241 PackageManager.DONT_KILL_APP); |
223 } | 242 } |
224 } | 243 } |
225 } | 244 } |
OLD | NEW |