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.annotation.SuppressLint; | |
7 import android.app.Activity; | 8 import android.app.Activity; |
8 import android.content.ActivityNotFoundException; | 9 import android.content.ActivityNotFoundException; |
9 import android.content.ComponentName; | 10 import android.content.ComponentName; |
10 import android.content.Intent; | 11 import android.content.Intent; |
11 import android.content.pm.PackageManager; | 12 import android.content.pm.PackageManager; |
12 import android.net.Uri; | 13 import android.net.Uri; |
13 import android.text.TextUtils; | 14 import android.text.TextUtils; |
14 import android.util.Base64; | 15 import android.util.Base64; |
15 import android.util.Log; | 16 import android.util.Log; |
16 | 17 |
18 import java.io.FileInputStream; | |
19 import java.io.IOException; | |
17 import java.security.SecureRandom; | 20 import java.security.SecureRandom; |
18 import java.util.ArrayList; | 21 import java.util.ArrayList; |
19 | 22 |
20 /** | 23 /** |
21 * This class is responsible for fetching a third party token from the user usin g the OAuth2 | 24 * This class is responsible for fetching a third party token from the user usin g the OAuth2 |
22 * implicit flow. It directs the user to a third party login page located at |t okenUrl|. It relies | 25 * implicit flow. It directs the user to a third party login page located at |t okenUrl|. It relies |
23 * on the |ThirdPartyTokenFetcher$OAuthRedirectActivity| to intercept the access token from the | 26 * on the |ThirdPartyTokenFetcher$OAuthRedirectActivity| to intercept the access token from the |
24 * redirect at intent://|REDIRECT_URI_PATH|#Intent;...end; upon successful login . | 27 * redirect at intent://|REDIRECT_URI_PATH|#Intent;...end; upon successful login . |
25 */ | 28 */ |
26 public class ThirdPartyTokenFetcher { | 29 public class ThirdPartyTokenFetcher { |
27 /** Callback for receiving the token. */ | 30 /** Callback for receiving the token. */ |
28 public interface Callback { | 31 public interface Callback { |
29 void onTokenFetched(String code, String accessToken); | 32 void onTokenFetched(String code, String accessToken); |
30 } | 33 } |
31 | 34 |
32 /** The path of the Redirect URI. */ | 35 /** The path of the Redirect URI. */ |
33 private static final String REDIRECT_URI_PATH = "/oauthredirect/"; | 36 private static final String REDIRECT_URI_PATH = "/oauthredirect/"; |
34 | 37 |
35 /** | 38 /** |
36 * Request both the authorization code and access token from the server. Se e | 39 * Request both the authorization code and access token from the server. Se e |
37 * http://tools.ietf.org/html/rfc6749#section-3.1.1. | 40 * http://tools.ietf.org/html/rfc6749#section-3.1.1. |
38 */ | 41 */ |
39 private static final String RESPONSE_TYPE = "code token"; | 42 private static final String RESPONSE_TYPE = "code token"; |
40 | 43 |
44 /** Used to initialize the random number generator. */ | |
45 private static final int NUM_RANDOM_BYTES = 16; | |
46 | |
41 /** This is used to securely generate an opaque 128 bit for the |mState| var iable. */ | 47 /** This is used to securely generate an opaque 128 bit for the |mState| var iable. */ |
42 private static SecureRandom sSecureRandom = new SecureRandom(); | 48 @SuppressLint("TrulyRandom") |
49 private static SecureRandom sSecureRandom; | |
50 | |
51 static { | |
52 // Versions of SecureRandom from Android <= 4.3 do not seed themselves a s | |
53 // securely as possible. This workaround should suffice until the fixed version | |
54 // is deployed to all users. It reads random data from /dev/urandom, whi ch is as good as | |
55 // the platform can get. | |
56 sSecureRandom = new SecureRandom(); | |
57 sSecureRandom.setSeed(getRandomBytes(NUM_RANDOM_BYTES)); | |
kelvinp
2014/08/13 02:33:26
As discussed, maybe it is better to move the initi
Lambros
2014/08/13 23:48:51
Discussed offline. The refactoring to do this is n
| |
58 } | |
43 | 59 |
44 /** This is used to launch the third party login page in the browser. */ | 60 /** This is used to launch the third party login page in the browser. */ |
45 private Activity mContext; | 61 private Activity mContext; |
46 | 62 |
47 /** | 63 /** |
48 * An opaque value used by the client to maintain state between the request and callback. The | 64 * An opaque value used by the client to maintain state between the request and callback. The |
49 * authorization server includes this value when redirecting the user-agent back to the client. | 65 * authorization server includes this value when redirecting the user-agent back to the client. |
50 * The parameter is used for preventing cross-site request forgery. See | 66 * The parameter is used for preventing cross-site request forgery. See |
51 * http://tools.ietf.org/html/rfc6749#section-10.12. | 67 * http://tools.ietf.org/html/rfc6749#section-10.12. |
52 */ | 68 */ |
53 private final String mState; | 69 private final String mState; |
54 | 70 |
55 private final Callback mCallback; | 71 private final Callback mCallback; |
56 | 72 |
57 /** The list of TokenUrls allowed by the domain. */ | 73 /** The list of TokenUrls allowed by the domain. */ |
58 private final ArrayList<String> mTokenUrlPatterns; | 74 private final ArrayList<String> mTokenUrlPatterns; |
59 | 75 |
60 private final String mRedirectUriScheme; | 76 private final String mRedirectUriScheme; |
61 | 77 |
62 private final String mRedirectUri; | 78 private final String mRedirectUri; |
63 | 79 |
80 private static byte[] getRandomBytes(int numBytes) { | |
81 FileInputStream fis = null; | |
82 try { | |
83 fis = new FileInputStream("/dev/urandom"); | |
84 byte[] bytes = new byte[numBytes]; | |
85 if (bytes.length != fis.read(bytes)) { | |
86 throw new SecurityException("Failed to get enough random data.") ; | |
87 } | |
88 return bytes; | |
89 } catch (IOException e) { | |
90 throw new SecurityException("Error reading random data."); | |
91 } finally { | |
92 try { | |
93 if (fis != null) { | |
94 fis.close(); | |
95 } | |
96 } catch (IOException e) { | |
97 // Ignore exception closing the device. | |
98 } | |
99 } | |
100 } | |
101 | |
64 public ThirdPartyTokenFetcher(Activity context, | 102 public ThirdPartyTokenFetcher(Activity context, |
65 ArrayList<String> tokenUrlPatterns, | 103 ArrayList<String> tokenUrlPatterns, |
66 Callback callback) { | 104 Callback callback) { |
67 this.mContext = context; | 105 this.mContext = context; |
68 this.mState = generateXsrfToken(); | 106 this.mState = generateXsrfToken(); |
69 this.mCallback = callback; | 107 this.mCallback = callback; |
70 this.mTokenUrlPatterns = tokenUrlPatterns; | 108 this.mTokenUrlPatterns = tokenUrlPatterns; |
71 | 109 |
72 this.mRedirectUriScheme = context.getApplicationContext().getPackageName (); | 110 this.mRedirectUriScheme = context.getApplicationContext().getPackageName (); |
73 | 111 |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
218 ComponentName component = new ComponentName( | 256 ComponentName component = new ComponentName( |
219 context.getApplicationContext(), | 257 context.getApplicationContext(), |
220 ThirdPartyTokenFetcher.OAuthRedirectActivity.class); | 258 ThirdPartyTokenFetcher.OAuthRedirectActivity.class); |
221 context.getPackageManager().setComponentEnabledSetting( | 259 context.getPackageManager().setComponentEnabledSetting( |
222 component, | 260 component, |
223 enabledState, | 261 enabledState, |
224 PackageManager.DONT_KILL_APP); | 262 PackageManager.DONT_KILL_APP); |
225 } | 263 } |
226 } | 264 } |
227 } | 265 } |
OLD | NEW |