diff --git a/README.md b/README.md
index 6c6eb4d..a8a428d 100644
--- a/README.md
+++ b/README.md
@@ -80,8 +80,24 @@ loginWidget.launch(this, new AuthorizationListener() {
The Login widget default configuration use Facebook and Google as authentication options.
If you configure only one of them the login widget will NOT launch and the user will be redirect to the configured idp authentication screen.
-
-
+
### Anonymous Login
```java
AppID.getInstance().loginAnonymously(getApplicationContext(), new AuthorizationListener() {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c7250e4..788ba0c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -16,6 +16,12 @@
+
+
+ android:text="Use Anonymously"
+ android:textSize="12sp" />
+
+
+ android:text="Protected Resource Request"
+ android:textAllCaps="false"
+ android:textSize="12sp" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/sign_in_strings.xml b/app/src/main/res/values/sign_in_strings.xml
new file mode 100644
index 0000000..fc6a7c0
--- /dev/null
+++ b/app/src/main/res/values/sign_in_strings.xml
@@ -0,0 +1,11 @@
+
+
+
+ Sign in
+
+ User Name
+ Password
+ Sign in
+ Sign in
+
+
\ No newline at end of file
diff --git a/lib/src/main/AndroidManifest.xml b/lib/src/main/AndroidManifest.xml
index 092a956..78c93f9 100644
--- a/lib/src/main/AndroidManifest.xml
+++ b/lib/src/main/AndroidManifest.xml
@@ -8,11 +8,6 @@
android:allowBackup="true"
android:supportsRtl="true">
-
-
-
diff --git a/lib/src/main/java/com/ibm/bluemix/appid/android/api/AppID.java b/lib/src/main/java/com/ibm/bluemix/appid/android/api/AppID.java
index 7216e05..8f74678 100644
--- a/lib/src/main/java/com/ibm/bluemix/appid/android/api/AppID.java
+++ b/lib/src/main/java/com/ibm/bluemix/appid/android/api/AppID.java
@@ -34,14 +34,17 @@ public class AppID {
private OAuthManager oAuthManager;
private UserAttributeManager userAttributeManager;
- public static String overrideOAuthServerHost = null; //when use place the assiment before calling the AppID initialize function
+ public static String overrideOAuthServerHost = null; //when use place the assignment before calling the AppID initialize function
public static String overrideUserProfilesHost = null;
public final static String REGION_US_SOUTH = ".ng.bluemix.net";
public final static String REGION_UK = ".eu-gb.bluemix.net";
public final static String REGION_SYDNEY = ".au-syd.bluemix.net";
+ public final static String REGION_GERMANY = ".eu-de.bluemix.net";
- // TODO: document
+ /**
+ * @return The AppID instance.
+ */
@NonNull
public static synchronized AppID getInstance(){
if (null == instance) {
@@ -56,7 +59,12 @@ public static synchronized AppID getInstance(){
private AppID(){}
- // TODO: document
+ /**
+ * @param context
+ * @param tenantId
+ * @param bluemixRegion
+ * @return The AppID instance tenantId.
+ */
@NonNull
public AppID initialize (@NonNull Context context, @NonNull String tenantId, @NonNull String bluemixRegion) {
this.tenantId = tenantId;
@@ -68,7 +76,7 @@ public AppID initialize (@NonNull Context context, @NonNull String tenantId, @No
}
/**
- * @return The AppID instance tenantId
+ * @return The AppID instance tenantId.
*/
@NonNull
public String getTenantId() {
@@ -89,14 +97,20 @@ public String getBluemixRegionSuffix() {
return this.bluemixRegionSuffix;
}
+ /**
+ * @return the login widget
+ */
@NonNull
- public LoginWidget getLoginWidget(){
+ public LoginWidget getLoginWidget() {
if (null == this.loginWidget){
throw new RuntimeException("AppID is not initialized. Use .initialize() first.");
}
return this.loginWidget;
}
+ /**
+ * @return the OAuth Manager
+ */
@NonNull
protected OAuthManager getOAuthManager(){
if (null == this.oAuthManager){
@@ -105,6 +119,9 @@ protected OAuthManager getOAuthManager(){
return this.oAuthManager;
}
+ /**
+ * @return the User Attribute Manager
+ */
@NonNull
public UserAttributeManager getUserAttributeManager(){
if (null == this.userAttributeManager){
@@ -124,6 +141,16 @@ public void loginAnonymously(@NotNull Context context, String accessToken, @NotN
public void loginAnonymously(@NotNull Context context, String accessToken, boolean allowCreateNewAnonymousUser, @NotNull AuthorizationListener authorizationListener){
oAuthManager.getAuthorizationManager().loginAnonymously(context, accessToken, allowCreateNewAnonymousUser, authorizationListener);
}
+ /**
+ * Obtain token using Resource owner Password (RoP).
+ *
+ * @param username the resource owner username
+ * @param password the resource owner password
+ * @param tokenResponseListener the token response listener
+ */
+ public void obtainTokensWithROP(@NotNull Context context, @NotNull String username, @NotNull String password, @NotNull TokenResponseListener tokenResponseListener) {
+ oAuthManager.getAuthorizationManager().obtainTokensWithROP(context, username, password, tokenResponseListener);
+ }
}
diff --git a/lib/src/main/java/com/ibm/bluemix/appid/android/api/AuthorizationListener.java b/lib/src/main/java/com/ibm/bluemix/appid/android/api/AuthorizationListener.java
index ae1b1ee..e94e158 100644
--- a/lib/src/main/java/com/ibm/bluemix/appid/android/api/AuthorizationListener.java
+++ b/lib/src/main/java/com/ibm/bluemix/appid/android/api/AuthorizationListener.java
@@ -13,11 +13,6 @@
package com.ibm.bluemix.appid.android.api;
-import com.ibm.bluemix.appid.android.api.tokens.AccessToken;
-import com.ibm.bluemix.appid.android.api.tokens.IdentityToken;
-
-public interface AuthorizationListener {
- void onAuthorizationFailure(AuthorizationException exception);
+public interface AuthorizationListener extends TokenResponseListener{
void onAuthorizationCanceled();
- void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identityToken);
}
diff --git a/lib/src/main/java/com/ibm/bluemix/appid/android/api/TokenResponseListener.java b/lib/src/main/java/com/ibm/bluemix/appid/android/api/TokenResponseListener.java
new file mode 100644
index 0000000..c435a54
--- /dev/null
+++ b/lib/src/main/java/com/ibm/bluemix/appid/android/api/TokenResponseListener.java
@@ -0,0 +1,22 @@
+/*
+ Copyright 2017 IBM Corp.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package com.ibm.bluemix.appid.android.api;
+
+import com.ibm.bluemix.appid.android.api.tokens.AccessToken;
+import com.ibm.bluemix.appid.android.api.tokens.IdentityToken;
+
+public interface TokenResponseListener {
+ void onAuthorizationFailure(AuthorizationException exception);
+ void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identityToken);
+}
diff --git a/lib/src/main/java/com/ibm/bluemix/appid/android/api/userattributes/UserAttributeManager.java b/lib/src/main/java/com/ibm/bluemix/appid/android/api/userattributes/UserAttributeManager.java
index 6f41cf1..777c8a2 100644
--- a/lib/src/main/java/com/ibm/bluemix/appid/android/api/userattributes/UserAttributeManager.java
+++ b/lib/src/main/java/com/ibm/bluemix/appid/android/api/userattributes/UserAttributeManager.java
@@ -19,14 +19,14 @@
public interface UserAttributeManager {
void setAttribute(@NonNull String name, @NonNull String value, UserAttributeResponseListener listener);
- void setAttribute(@NonNull String name, @NonNull String value, @NonNull AccessToken accessToken, UserAttributeResponseListener listener);
+ void setAttribute(@NonNull String name, @NonNull String value, AccessToken accessToken, UserAttributeResponseListener listener);
void getAttribute(@NonNull String name, UserAttributeResponseListener listener);
- void getAttribute(@NonNull String name, @NonNull AccessToken accessToken, UserAttributeResponseListener listener);
+ void getAttribute(@NonNull String name, AccessToken accessToken, UserAttributeResponseListener listener);
void deleteAttribute(@NonNull String name, UserAttributeResponseListener listener);
- void deleteAttribute(@NonNull String name, @NonNull AccessToken accessToken, UserAttributeResponseListener listener);
+ void deleteAttribute(@NonNull String name, AccessToken accessToken, UserAttributeResponseListener listener);
void getAllAttributes(@NonNull UserAttributeResponseListener listener);
- void getAllAttributes(@NonNull AccessToken accessToken, @NonNull UserAttributeResponseListener listener);
+ void getAllAttributes(AccessToken accessToken, @NonNull UserAttributeResponseListener listener);
}
diff --git a/lib/src/main/java/com/ibm/bluemix/appid/android/api/userattributes/UserAttributesException.java b/lib/src/main/java/com/ibm/bluemix/appid/android/api/userattributes/UserAttributesException.java
index 0d36b34..7083a2d 100644
--- a/lib/src/main/java/com/ibm/bluemix/appid/android/api/userattributes/UserAttributesException.java
+++ b/lib/src/main/java/com/ibm/bluemix/appid/android/api/userattributes/UserAttributesException.java
@@ -30,6 +30,11 @@ public String getDescription(){
public String getDescription(){
return "Access to attribute is unauthorized";
}
+ },
+ JSON_PARSE_ERROR {
+ public String getDescription(){
+ return "Response text is not a valid JSON format";
+ }
};
public abstract String getDescription();
diff --git a/lib/src/main/java/com/ibm/bluemix/appid/android/internal/authorizationmanager/AuthorizationManager.java b/lib/src/main/java/com/ibm/bluemix/appid/android/internal/authorizationmanager/AuthorizationManager.java
index 95383df..9d34ac4 100644
--- a/lib/src/main/java/com/ibm/bluemix/appid/android/internal/authorizationmanager/AuthorizationManager.java
+++ b/lib/src/main/java/com/ibm/bluemix/appid/android/internal/authorizationmanager/AuthorizationManager.java
@@ -20,6 +20,7 @@
import com.ibm.bluemix.appid.android.api.AppID;
import com.ibm.bluemix.appid.android.api.AuthorizationException;
import com.ibm.bluemix.appid.android.api.AuthorizationListener;
+import com.ibm.bluemix.appid.android.api.TokenResponseListener;
import com.ibm.bluemix.appid.android.api.tokens.AccessToken;
import com.ibm.bluemix.appid.android.internal.OAuthManager;
import com.ibm.bluemix.appid.android.internal.config.Config;
@@ -59,7 +60,11 @@ public class AuthorizationManager {
private final static Logger logger = Logger.getLogger(Logger.INTERNAL_PREFIX + AuthorizationManager.class.getName());
- // TODO: document
+ /**
+ * @param oAuthManager
+ * @param ctx the Context that will be bind to the custom chrome tab.
+ * The AuthorizationManager constructor.
+ */
public AuthorizationManager (final OAuthManager oAuthManager, final Context ctx) {
this.oAuthManager = oAuthManager;
this.appId = oAuthManager.getAppId();
@@ -68,8 +73,10 @@ public AuthorizationManager (final OAuthManager oAuthManager, final Context ctx)
AuthorizationUIManager.bindCustomTabsService(ctx, serverUrl);
}
- // TODO: document
- public String getAuthorizationUrl(String idpName, AccessToken accessToken) {
+ /**
+ * @return The Authorization endpoint url.
+ */
+ private String getAuthorizationUrl(String idpName, AccessToken accessToken) {
String clientId = registrationManager.getRegistrationDataString(RegistrationManager.CLIENT_ID);
String redirectUri = registrationManager.getRegistrationDataString(RegistrationManager.REDIRECT_URIS, 0);
@@ -92,7 +99,12 @@ public void launchAuthorizationUI (final Activity activity, final AuthorizationL
launchAuthorizationUI(activity, null, authorizationListener);
}
- // TODO: document
+ /**
+ * @param activity the activity to launch the chrome tab on to.
+ * @param accessToken if not null, this access token will be added to the request.
+ * @param authorizationListener the authorization listener of the client.
+ * launch the authorization url in the chrome tab after successful registration.
+ */
public void launchAuthorizationUI (final Activity activity, final AccessToken accessToken, final AuthorizationListener authorizationListener){
registrationManager.ensureRegistered(activity, new RegistrationListener() {
@Override
@@ -111,7 +123,7 @@ public void onRegistrationSuccess () {
});
}
- public void continueAnonymousLogin (String accessTokenString, boolean allowCreateNewAnonymousUser, final AuthorizationListener listener){
+ private void continueAnonymousLogin (String accessTokenString, boolean allowCreateNewAnonymousUser, final AuthorizationListener listener){
AccessToken accessToken;
if (accessTokenString == null){
accessToken = oAuthManager.getTokenManager().getLatestAccessToken();
@@ -142,7 +154,7 @@ public void onFailure(Response response, Throwable t, JSONObject extendedInfo) {
String message = (response == null) ? "" : response.getResponseText();
logger.debug("loginAnonymously.Response in onFailure:" + message, t);
message = (t != null) ? t.getLocalizedMessage() : "Authorization request failed.";
- message = (extendedInfo !=null) ? message + extendedInfo.toString() : message;
+ message = (extendedInfo != null) ? message + extendedInfo.toString() : message;
listener.onAuthorizationFailure(new AuthorizationException(message));
}
}
@@ -154,7 +166,7 @@ public void loginAnonymously(final Context context, final String accessTokenStri
@Override
public void onRegistrationFailure (RegistrationStatus error) {
logger.error(error.getDescription());
- authorizationListener.onAuthorizationFailure(new AuthorizationException(error.getDescription()));
+ authorizationListener.onAuthorizationFailure(new AuthorizationException(error.getDescription()));
}
@Override
@@ -167,4 +179,22 @@ public void onRegistrationSuccess () {
public void setAppIDRequestFactory(AppIDRequestFactory appIDRequestFactory) {
this.appIDRequestFactory = appIDRequestFactory;
}
+
+ public void obtainTokensWithROP(final Context context, final String username, final String password, final TokenResponseListener tokenResponseListener) {
+ registrationManager.ensureRegistered(context, new RegistrationListener() {
+ @Override
+ public void onRegistrationFailure (RegistrationStatus error) {
+ logger.error(error.getDescription());
+ tokenResponseListener.onAuthorizationFailure(new AuthorizationException(error.getDescription()));
+ }
+
+ @Override
+ public void onRegistrationSuccess () {
+ oAuthManager.getTokenManager().obtainTokens(username, password, tokenResponseListener);
+ }
+ });
+ }
+
+
+
}
diff --git a/lib/src/main/java/com/ibm/bluemix/appid/android/internal/authorizationmanager/AuthorizationUIManager.java b/lib/src/main/java/com/ibm/bluemix/appid/android/internal/authorizationmanager/AuthorizationUIManager.java
index 36308e6..db08061 100644
--- a/lib/src/main/java/com/ibm/bluemix/appid/android/internal/authorizationmanager/AuthorizationUIManager.java
+++ b/lib/src/main/java/com/ibm/bluemix/appid/android/internal/authorizationmanager/AuthorizationUIManager.java
@@ -46,9 +46,9 @@ class AuthorizationUIManager {
private static final String DEV_PACKAGE = "com.chrome.dev";
private static final String LOCAL_PACKAGE = "com.google.android.apps.chrome";
private static final String ACTION_CUSTOM_TABS_CONNECTION = "android.support.customtabs.action.CustomTabsService";
- public static final String EXTRA_URL = "com.ibm.bluemix.appid.android.URL";
- public static final String EXTRA_AUTH_FLOW_CONTEXT_GUID = "com.ibm.bluemix.appid.android.AUTH_FLOW_CONTEXT_GUID";
- public static final String EXTRA_REDIRECT_URL = "com.ibm.bluemix.appid.android.REDIRECT_URL";
+ static final String EXTRA_URL = "com.ibm.bluemix.appid.android.URL";
+ static final String EXTRA_AUTH_FLOW_CONTEXT_GUID = "com.ibm.bluemix.appid.android.AUTH_FLOW_CONTEXT_GUID";
+ static final String EXTRA_REDIRECT_URL = "com.ibm.bluemix.appid.android.REDIRECT_URL";
private static CustomTabsClient mClient;
private static CustomTabsSession mCustomTabsSession;
@@ -64,13 +64,18 @@ class AuthorizationUIManager {
private static boolean isChromeTabSupported = true;
// TODO: document
- public AuthorizationUIManager(OAuthManager oAuthManager, AuthorizationListener authorizationListener, String serverUrl, String redirectUrl) {
+ AuthorizationUIManager(OAuthManager oAuthManager, AuthorizationListener authorizationListener, String serverUrl, String redirectUrl) {
this.oAuthManager = oAuthManager;
this.authorizationListener = authorizationListener;
this.serverUrl = serverUrl;
this.redirectUrl = redirectUrl;
}
+ //for testing
+ Intent createChromeTabIntent(Activity activity) {
+ return new Intent(activity, ChromeTabActivity.class);
+ }
+
public void launch(final Activity activity) {
final Context context = activity.getApplicationContext();
String authFlowContextGuid = UUID.randomUUID().toString();
@@ -82,29 +87,15 @@ public void launch(final Activity activity) {
// (There might be a browser other than Chrome that support Chrome tabs)
if (getPackageNameToUse(context) == null || !isChromeTabSupported) {
- // Use WebView ,Authorization request with a Webview will be blocked on April 20, 2017
-// logger.debug("Launching WebViewActivity");
-// try {
-// Intent intent = new Intent(context, WebViewActivity.class);
-// intent.putExtra(EXTRA_AUTH_FLOW_CONTEXT_GUID, authFlowContextGuid);
-// intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-// intent.putExtra(EXTRA_URL, serverUrl);
-// intent.putExtra(EXTRA_REDIRECT_URL, redirectUrl);
-// context.startActivity(intent);
-// } catch (ActivityNotFoundException e) {
-// logger.error("Activity not found", e);
-// authorizationListener.onAuthorizationFailure(new AuthorizationException(e.getMessage()));
-// }
- authorizationListener.onAuthorizationFailure(new AuthorizationException("Can NOT find installed browser that support Chrome tabs on the device."));
+ authorizationListener.onAuthorizationFailure(new AuthorizationException("Could NOT find installed browser that support Chrome tabs on the device."));
} else {
// Use Chrome tabs
logger.debug("Launching ChromeTabActivity");
- Intent intent = new Intent(activity, ChromeTabActivity.class);
+ Intent intent = createChromeTabIntent(activity);
intent.putExtra(EXTRA_AUTH_FLOW_CONTEXT_GUID, authFlowContextGuid);
intent.putExtra(EXTRA_REDIRECT_URL, redirectUrl);
intent.putExtra(EXTRA_URL, serverUrl);
// Open ChromeTabActivity that will open the ChromeTab on top of it
- intent.putExtra(EXTRA_URL, serverUrl);
activity.startActivity(intent);
}
}
@@ -243,5 +234,10 @@ public void onNavigationEvent(int navigationEvent, Bundle extras) {
return mCustomTabsSession;
}
+ //for testing
+ void reset_sPackageNameToUse(){
+ sPackageNameToUse = null;
+ }
+
}
diff --git a/lib/src/main/java/com/ibm/bluemix/appid/android/internal/authorizationmanager/ChromeTabActivity.java b/lib/src/main/java/com/ibm/bluemix/appid/android/internal/authorizationmanager/ChromeTabActivity.java
index 5676aa7..5c93ee8 100644
--- a/lib/src/main/java/com/ibm/bluemix/appid/android/internal/authorizationmanager/ChromeTabActivity.java
+++ b/lib/src/main/java/com/ibm/bluemix/appid/android/internal/authorizationmanager/ChromeTabActivity.java
@@ -72,11 +72,6 @@ public void onCreate(Bundle savedInstanceBundle) {
customTabsIntent.intent.setPackage(AuthorizationUIManager.getPackageNameToUse(this.getApplicationContext()));
customTabsIntent.intent.addFlags(PendingIntent.FLAG_ONE_SHOT);
- //This will launch the chrome tab
- Uri uri = Uri.parse(serverUrl);
- logger.debug("launching custom tab with url: " + uri.toString());
- customTabsIntent.launchUrl(this, uri);
-
broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -87,6 +82,11 @@ public void onReceive(Context context, Intent intent) {
IntentFilter intentFilter = new IntentFilter(INTENT_GOT_HTTP_REDIRECT);
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, intentFilter);
+ //This will launch the chrome tab
+ Uri uri = Uri.parse(serverUrl);
+ logger.debug("launching custom tab with url: " + uri.toString());
+ customTabsIntent.launchUrl(this, uri);
+
} else {
//if we launch after authorization completed
finish();
diff --git a/lib/src/main/java/com/ibm/bluemix/appid/android/internal/authorizationmanager/WebViewActivity.java b/lib/src/main/java/com/ibm/bluemix/appid/android/internal/authorizationmanager/WebViewActivity.java
deleted file mode 100755
index 123f0a9..0000000
--- a/lib/src/main/java/com/ibm/bluemix/appid/android/internal/authorizationmanager/WebViewActivity.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- Copyright 2017 IBM Corp.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-
-package com.ibm.bluemix.appid.android.internal.authorizationmanager;
-
-import android.net.Uri;
-import android.os.Build;
-import android.support.annotation.RequiresApi;
-import android.support.v7.app.AppCompatActivity;
-import android.os.Bundle;
-import android.view.ViewGroup;
-import android.webkit.WebResourceRequest;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-
-import com.ibm.bluemix.appid.android.api.AuthorizationException;
-import com.ibm.bluemix.appid.android.api.AuthorizationListener;
-import com.ibm.bluemix.appid.android.internal.OAuthManager;
-import com.ibm.mobilefirstplatform.appid_clientsdk_android.R;
-import com.ibm.mobilefirstplatform.clientsdk.android.logger.api.Logger;
-
-public class WebViewActivity extends AppCompatActivity {
-
- private AuthorizationListener authorizationListener;
- private OAuthManager oAuthManager;
- private String redirectUrl;
-
- private static final Logger logger = Logger.getLogger(Logger.INTERNAL_PREFIX + WebViewActivity.class.getName());
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- logger.debug("onCreate");
- setContentView(R.layout.activity_web_view);
- WebView webView = (WebView) findViewById(R.id.webView1);
- webView.getSettings().setJavaScriptEnabled(true);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- webView.setWebViewClient(new WebViewClientNewAPI());
- }else{
- webView.setWebViewClient(new WebViewClientOldAPI());
- }
- webView.clearCache(true);
-
- String serverUrl = getIntent().getStringExtra(AuthorizationUIManager.EXTRA_URL);
- this.redirectUrl = getIntent().getStringExtra(AuthorizationUIManager.EXTRA_REDIRECT_URL);
-
- String authFlowContextGuid = getIntent().getStringExtra(AuthorizationUIManager.EXTRA_AUTH_FLOW_CONTEXT_GUID);
- AuthorizationFlowContext ctx = AuthorizationFlowContextStore.remove(authFlowContextGuid);
-
- this.oAuthManager = ctx.getOAuthManager();
- this.authorizationListener = ctx.getAuthorizationListener();
-
- logger.debug("serverUrl: " + serverUrl);
- logger.debug("redirectUrl: " + redirectUrl);
-
- if (authorizationListener == null || serverUrl == null || this.redirectUrl == null){
- logger.error("Failed to retrieve one of the following: authorizationListener, serverUrl, redirectUrl");
- finish();
- } else {
- webView.loadUrl(serverUrl);
- }
- }
-
- //override here in order to avoid window leaks
- @Override
- public void finish() {
- ViewGroup view = (ViewGroup) getWindow().getDecorView();
- view.removeAllViews();
- super.finish();
- }
-
- @Override
- public void onBackPressed() {
- finish();
- authorizationListener.onAuthorizationCanceled();
- }
-
- private class WebViewClientOldAPI extends WebViewClient {
- @Override
- public boolean shouldOverrideUrlLoading(final WebView view, String url) {
- Uri uri = Uri.parse(url);
- loadUri(view, uri);
- return true;
- }
- }
-
- private class WebViewClientNewAPI extends WebViewClient {
- @RequiresApi (api = Build.VERSION_CODES.LOLLIPOP)
- @Override
- public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
- Uri uri = request.getUrl();
- loadUri(view, uri);
- return true;
- }
- }
-
- private void loadUri(WebView view, Uri uri) {
- String url = uri.toString();
- String code = uri.getQueryParameter("code");
- String error = uri.getQueryParameter("error");
- if (url.startsWith(redirectUrl) && code != null) {
- logger.debug("Grant code received from authorization server.");
- finish();
- oAuthManager.getTokenManager().obtainTokens(code, authorizationListener);
-
- } else if (url.startsWith(redirectUrl) && error != null){
- String errorCode = uri.getQueryParameter("error_code");
- String errorDescription = uri.getQueryParameter("error_description");
- logger.error("error: " + error);
- logger.error("errorCode: " + errorCode);
- logger.error("errorDescription: " + errorDescription);
- authorizationListener.onAuthorizationFailure(new AuthorizationException("Failed to obtain access and identity tokens"));
- finish();
- } else {
- //when working locally uncomment this 'if' (replacing localhost with 10.0.2.2)
- // if(AppID.overrideOAuthServerHost != null && uri.getHost().equals("localhost")) {
- //when working locally replacing localhost with 10.0.2.2
- // url = AppID.overrideOAuthServerHost.replace("/oauth/v3/","") + url.substring(21, url.length());
- // }
- view.loadUrl(url);
- }
- }
-}
diff --git a/lib/src/main/java/com/ibm/bluemix/appid/android/internal/tokenmanager/TokenManager.java b/lib/src/main/java/com/ibm/bluemix/appid/android/internal/tokenmanager/TokenManager.java
index c0c943b..cae0793 100644
--- a/lib/src/main/java/com/ibm/bluemix/appid/android/internal/tokenmanager/TokenManager.java
+++ b/lib/src/main/java/com/ibm/bluemix/appid/android/internal/tokenmanager/TokenManager.java
@@ -18,6 +18,7 @@
import com.ibm.bluemix.appid.android.api.AppID;
import com.ibm.bluemix.appid.android.api.AuthorizationException;
import com.ibm.bluemix.appid.android.api.AuthorizationListener;
+import com.ibm.bluemix.appid.android.api.TokenResponseListener;
import com.ibm.bluemix.appid.android.api.tokens.AccessToken;
import com.ibm.bluemix.appid.android.api.tokens.IdentityToken;
import com.ibm.bluemix.appid.android.internal.OAuthManager;
@@ -30,7 +31,6 @@
import com.ibm.mobilefirstplatform.clientsdk.android.core.api.ResponseListener;
import com.ibm.mobilefirstplatform.clientsdk.android.logger.api.Logger;
-import org.json.JSONException;
import org.json.JSONObject;
import java.security.PrivateKey;
@@ -54,22 +54,42 @@ public class TokenManager {
private final static String CODE = "code";
private final static String REDIRECT_URI = "redirect_uri";
private final static String AUTHORIZATION_HEADER = "Authorization";
-
+ private final static String USERNAME = "username";
+ private final static String PASSWORD = "password";
+ private final static String GRANT_TYPE_PASSWORD = "password";
+ private final static String ERROR_DESCRIPTION= "error_description";
+ private final static String ERROR_CODE= "error";
+ private final static String INVALID_GRANT= "invalid_grant";
public TokenManager (OAuthManager oAuthManager) {
this.appId = oAuthManager.getAppId();
this.registrationManager = oAuthManager.getRegistrationManager();
}
-
public void obtainTokens (String code, final AuthorizationListener listener) {
logger.debug("obtainTokens");
- String tokenUrl = Config.getOAuthServerUrl(appId) + OAUTH_TOKEN_PATH;
-
String clientId = registrationManager.getRegistrationDataString(RegistrationManager.CLIENT_ID);
String redirectUri = registrationManager.getRegistrationDataString(RegistrationManager.REDIRECT_URIS, 0);
- AppIDRequest request = new AppIDRequest(tokenUrl, "POST");
+ HashMap formParams = new HashMap<>();
+ formParams.put(CODE, code);
+ formParams.put(CLIENT_ID, clientId);
+ formParams.put(GRANT_TYPE, GRANT_TYPE_AUTH_CODE);
+ formParams.put(REDIRECT_URI, redirectUri);
+
+ retrieveTokens(formParams, listener);
+ }
+
+ //for testing purpose
+ AppIDRequest createAppIDRequest(String url, String method) {
+ return new AppIDRequest(url, method);
+ }
+
+ private void retrieveTokens(HashMap formParams, final TokenResponseListener listener) {
+ String tokenUrl = Config.getOAuthServerUrl(appId) + OAUTH_TOKEN_PATH;
+ String clientId = registrationManager.getRegistrationDataString(RegistrationManager.CLIENT_ID);
+
+ AppIDRequest request = createAppIDRequest(tokenUrl, "POST");
try {
request.addHeader(AUTHORIZATION_HEADER, createAuthenticationHeader(clientId));
@@ -78,17 +98,25 @@ public void obtainTokens (String code, final AuthorizationListener listener) {
return;
}
- HashMap formParams = new HashMap<>();
- formParams.put(CODE, code);
- formParams.put(CLIENT_ID, clientId);
- formParams.put(GRANT_TYPE, GRANT_TYPE_AUTH_CODE);
- formParams.put(REDIRECT_URI, redirectUri);
-
request.send(formParams, new ResponseListener() {
@Override
public void onFailure (Response response, Throwable t, JSONObject extendedInfo) {
logger.error("Failed to retrieve tokens from authorization server", t);
- listener.onAuthorizationFailure(new AuthorizationException("Failed to retrieve tokens"));
+ String errorDescription = "";
+ try {
+ if (response.getStatus() == 400) {
+ JSONObject responseJSON = new JSONObject(response.getResponseText());
+ if (INVALID_GRANT.equals(responseJSON.getString(ERROR_CODE))) {
+ errorDescription = responseJSON.getString(ERROR_DESCRIPTION);
+ listener.onAuthorizationFailure(new AuthorizationException("Failed to retrieve tokens: " + errorDescription));
+ return;
+ }
+ }
+ listener.onAuthorizationFailure(new AuthorizationException("Failed to retrieve tokens"));
+ } catch (Exception e) {
+ logger.error("Failed to retrieve tokens from authorization server", t);
+ listener.onAuthorizationFailure(new AuthorizationException("Failed to retrieve tokens"));
+ }
}
@Override
@@ -98,6 +126,16 @@ public void onSuccess (Response response) {
});
}
+ public void obtainTokens (String username, String password, final TokenResponseListener listener) {
+ logger.debug("obtainTokens - with resource owner password");
+
+ HashMap formParams = new HashMap<>();
+ formParams.put(USERNAME, username);
+ formParams.put(PASSWORD, password);
+ formParams.put(GRANT_TYPE, GRANT_TYPE_PASSWORD);
+
+ retrieveTokens(formParams, listener);
+ }
private String createAuthenticationHeader (String clientId) throws Exception {
PrivateKey privateKey = registrationManager.getPrivateKey();
@@ -113,7 +151,7 @@ private String createAuthenticationHeader (String clientId) throws Exception {
*
* @param response response that contain the token
*/
- private void extractTokens (Response response, AuthorizationListener authorizationListener) {
+ private void extractTokens (Response response, TokenResponseListener tokenResponseListener) {
String accessTokenString;
String idTokenString;
AccessToken accessToken;
@@ -125,9 +163,9 @@ private void extractTokens (Response response, AuthorizationListener authorizati
JSONObject responseJSON = new JSONObject(response.getResponseText());
accessTokenString = responseJSON.getString("access_token");
idTokenString = responseJSON.getString("id_token");
- } catch (JSONException e){
+ } catch (Exception e){
logger.error("Failed to parse server response", e);
- authorizationListener.onAuthorizationFailure(new AuthorizationException("Failed to parse server response"));
+ tokenResponseListener.onAuthorizationFailure(new AuthorizationException("Failed to parse server response"));
return;
}
@@ -135,7 +173,7 @@ private void extractTokens (Response response, AuthorizationListener authorizati
accessToken = new AccessTokenImpl(accessTokenString);
} catch (RuntimeException e){
logger.error("Failed to parse access_token", e);
- authorizationListener.onAuthorizationFailure(new AuthorizationException("Failed to parse access_token"));
+ tokenResponseListener.onAuthorizationFailure(new AuthorizationException("Failed to parse access_token"));
return;
}
@@ -144,14 +182,14 @@ private void extractTokens (Response response, AuthorizationListener authorizati
} catch (RuntimeException e){
clearStoredTokens();
logger.error("Failed to parse id_token", e);
- authorizationListener.onAuthorizationFailure(new AuthorizationException("Failed to parse id_token"));
+ tokenResponseListener.onAuthorizationFailure(new AuthorizationException("Failed to parse id_token"));
return;
}
latestAccessToken = accessToken;
latestIdentityToken = identityToken;
- authorizationListener.onAuthorizationSuccess(accessToken, identityToken);
+ tokenResponseListener.onAuthorizationSuccess(accessToken, identityToken);
}
public AccessToken getLatestAccessToken () {
diff --git a/lib/src/main/java/com/ibm/bluemix/appid/android/internal/userattributesmanager/UserAttributeManagerImpl.java b/lib/src/main/java/com/ibm/bluemix/appid/android/internal/userattributesmanager/UserAttributeManagerImpl.java
index fa9bede..7927084 100644
--- a/lib/src/main/java/com/ibm/bluemix/appid/android/internal/userattributesmanager/UserAttributeManagerImpl.java
+++ b/lib/src/main/java/com/ibm/bluemix/appid/android/internal/userattributesmanager/UserAttributeManagerImpl.java
@@ -45,16 +45,14 @@ public UserAttributeManagerImpl(TokenManager tokenManager){
@Override
public void setAttribute (@NonNull String name, @NonNull String value, UserAttributeResponseListener listener) {
-
this.setAttribute(name, value, null, listener);
}
@Override
- public void setAttribute (@NonNull String name, @NonNull String value, @NonNull AccessToken accessToken, final UserAttributeResponseListener listener) {
- if(accessToken == null){
+ public void setAttribute (@NonNull String name, @NonNull String value, AccessToken accessToken, final UserAttributeResponseListener listener) {
+ if(accessToken == null) {
accessToken = tokenManager.getLatestAccessToken();
}
-
sendProtectedRequest(AppIDRequest.PUT, name, value, accessToken, listener);
}
@@ -64,7 +62,7 @@ public void getAttribute (@NonNull String name, UserAttributeResponseListener li
}
@Override
- public void getAttribute (@NonNull String name, @NonNull AccessToken accessToken, UserAttributeResponseListener listener) {
+ public void getAttribute (@NonNull String name, AccessToken accessToken, UserAttributeResponseListener listener) {
if(accessToken == null){
accessToken = tokenManager.getLatestAccessToken();
}
@@ -77,7 +75,7 @@ public void deleteAttribute (@NonNull String name, UserAttributeResponseListener
}
@Override
- public void deleteAttribute (@NonNull String name, @NonNull AccessToken accessToken, UserAttributeResponseListener listener) {
+ public void deleteAttribute (@NonNull String name, AccessToken accessToken, UserAttributeResponseListener listener) {
if(accessToken == null){
accessToken = tokenManager.getLatestAccessToken();
}
@@ -90,18 +88,27 @@ public void getAllAttributes(@NonNull UserAttributeResponseListener listener) {
}
@Override
- public void getAllAttributes(@NonNull AccessToken accessToken, @NonNull UserAttributeResponseListener listener) {
- if(accessToken == null){
+ public void getAllAttributes(AccessToken accessToken, @NonNull UserAttributeResponseListener listener) {
+ if (accessToken == null) {
accessToken = tokenManager.getLatestAccessToken();
}
sendProtectedRequest(AppIDRequest.GET, null, null, accessToken, listener);
}
+ //for testing purpose
+ AppIDRequest createAppIDRequest(String url, String method) {
+ return new AppIDRequest(url, method);
+ }
+ //for testing purpose
+ RequestBody createRequestBody(String value) {
+ return RequestBody.create(MediaType.parse("application/json"), value);
+ }
+
private void sendProtectedRequest(String method, String name, String value, AccessToken accessToken, final UserAttributeResponseListener listener){
String url = Config.getUserProfilesServerUrl(AppID.getInstance()) + USER_PROFILE_ATTRIBUTES_PATH;
url = (name == null || name.length() == 0) ? url : url + '/' + name;
- AppIDRequest req = new AppIDRequest(url, method);
+ AppIDRequest req = createAppIDRequest(url, method);
ResponseListener resListener = new ResponseListener() {
@Override
@@ -111,6 +118,7 @@ public void onSuccess(Response response) {
try {
listener.onSuccess(new JSONObject(responseText));
} catch (JSONException e) {
+ listener.onFailure(new UserAttributesException(UserAttributesException.Error.JSON_PARSE_ERROR));
e.printStackTrace();
}
}
@@ -134,7 +142,7 @@ public void onFailure(Response response, Throwable t, JSONObject extendedInfo) {
};
RequestBody requestBody =
- (value == null || value.length() == 0) ? null : RequestBody.create(MediaType.parse("application/json"), value);
+ (value == null || value.length() == 0) ? null : createRequestBody(value);
req.send (resListener, requestBody, accessToken);
}
diff --git a/lib/src/test/java/com/ibm/bluemix/appid/android/TestSuite.java b/lib/src/test/java/com/ibm/bluemix/appid/android/TestSuite.java
index 4621744..a0fcb54 100644
--- a/lib/src/test/java/com/ibm/bluemix/appid/android/TestSuite.java
+++ b/lib/src/test/java/com/ibm/bluemix/appid/android/TestSuite.java
@@ -21,10 +21,17 @@
import com.ibm.bluemix.appid.android.api.tokens.IdentityToken_Test;
import com.ibm.bluemix.appid.android.api.tokens.OAuthClient_Test;
import com.ibm.bluemix.appid.android.api.userattributes.UserAttributesException_Test;
+import com.ibm.bluemix.appid.android.internal.authorizationmanager.AuthorizationManager_Test;
+import com.ibm.bluemix.appid.android.internal.authorizationmanager.AuthorizationUIManager_Test;
import com.ibm.bluemix.appid.android.internal.helpers.AuthorizationHeaderHelper_Test;
+import com.ibm.bluemix.appid.android.internal.loginwidget.LoginWidgetImpl_Test;
+import com.ibm.bluemix.appid.android.internal.network.AppIDRequestFactory_Test;
+import com.ibm.bluemix.appid.android.internal.network.AppIDRequest_Test;
import com.ibm.bluemix.appid.android.internal.preferences.JSONPreference_Test;
import com.ibm.bluemix.appid.android.internal.preferences.StringPreference_Test;
+import com.ibm.bluemix.appid.android.internal.tokenmanager.TokenManager_Test;
import com.ibm.bluemix.appid.android.internal.tokens.AbstractToken_Test;
+import com.ibm.bluemix.appid.android.internal.userattributesmanager.UserAttributeManagerImpl_Test;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@@ -46,6 +53,13 @@
AuthorizationHeaderHelper_Test.class,
StringPreference_Test.class,
JSONPreference_Test.class,
- Config_Test.class
+ Config_Test.class,
+ AuthorizationManager_Test.class,
+ TokenManager_Test.class,
+ AuthorizationUIManager_Test.class,
+ UserAttributeManagerImpl_Test.class,
+ AppIDRequest_Test.class,
+ AppIDRequestFactory_Test.class,
+ LoginWidgetImpl_Test.class
})
public class TestSuite {}
diff --git a/lib/src/test/java/com/ibm/bluemix/appid/android/api/AppIDAuthorizationManager_Test.java b/lib/src/test/java/com/ibm/bluemix/appid/android/api/AppIDAuthorizationManager_Test.java
index e375c6d..f3bb71e 100644
--- a/lib/src/test/java/com/ibm/bluemix/appid/android/api/AppIDAuthorizationManager_Test.java
+++ b/lib/src/test/java/com/ibm/bluemix/appid/android/api/AppIDAuthorizationManager_Test.java
@@ -13,6 +13,7 @@
package com.ibm.bluemix.appid.android.api;
+import android.app.Activity;
import android.os.Build;
import com.ibm.bluemix.appid.android.api.tokens.AccessToken;
@@ -25,17 +26,23 @@
import com.ibm.bluemix.appid.android.testing.helpers.Consts;
import com.ibm.bluemix.appid.android.testing.mocks.HttpURLConnection_Mock;
import com.ibm.mobilefirstplatform.appid_clientsdk_android.BuildConfig;
+import com.ibm.mobilefirstplatform.clientsdk.android.core.api.Response;
+import com.ibm.mobilefirstplatform.clientsdk.android.core.api.ResponseListener;
import com.ibm.mobilefirstplatform.clientsdk.android.security.api.AppIdentity;
import com.ibm.mobilefirstplatform.clientsdk.android.security.api.DeviceIdentity;
import com.ibm.mobilefirstplatform.clientsdk.android.security.api.UserIdentity;
+import org.json.JSONObject;
import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@@ -47,6 +54,7 @@
import java.util.Map;
+import static junit.framework.Assert.assertEquals;
import static org.assertj.core.api.Java6Assertions.*;
import static org.mockito.Mockito.*;
@@ -182,4 +190,83 @@ public void testLogout(){
appIdAuthManager.logout(RuntimeEnvironment.application, null);
verify(tokenManagerMock, times(2)).clearStoredTokens();
}
+
+ @Test
+ public void obtainAuthorization_test_onAuthorizationSuccess(){
+ Mockito.doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ AuthorizationListener authorizationListener = (AuthorizationListener) args[1];
+ authorizationListener.onAuthorizationSuccess(accessToken,idToken);
+ return null;
+ }
+ }).when(authorizationManagerMock).launchAuthorizationUI(any(Activity.class), any(AuthorizationListener.class));
+
+
+ appIdAuthManager.obtainAuthorization(Mockito.mock(Activity.class), new ResponseListener() {
+ @Override
+ public void onSuccess(Response response) {
+ assertEquals(response, null);
+ }
+
+ @Override
+ public void onFailure(Response response, Throwable t, JSONObject extendedInfo) {
+ fail("should get to onSuccess");
+ }
+ }, null);
+ }
+
+ @Test
+ public void obtainAuthorization_test_onAuthorizationFailure(){
+ Mockito.doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ AuthorizationListener authorizationListener = (AuthorizationListener) args[1];
+ authorizationListener.onAuthorizationFailure(new AuthorizationException("test exception"));
+ return null;
+ }
+ }).when(authorizationManagerMock).launchAuthorizationUI(any(Activity.class), any(AuthorizationListener.class));
+
+
+ appIdAuthManager.obtainAuthorization(Mockito.mock(Activity.class), new ResponseListener() {
+ @Override
+ public void onSuccess(Response response) {
+ fail("should get to onFailure");
+ }
+
+ @Override
+ public void onFailure(Response response, Throwable t, JSONObject extendedInfo) {
+ assertEquals(t.getMessage(), "test exception");
+ }
+ }, null);
+ }
+
+ @Test
+ public void obtainAuthorization_test_onAuthorizationCanceled(){
+ Mockito.doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ AuthorizationListener authorizationListener = (AuthorizationListener) args[1];
+ authorizationListener.onAuthorizationCanceled();
+ return null;
+ }
+ }).when(authorizationManagerMock).launchAuthorizationUI(any(Activity.class), any(AuthorizationListener.class));
+
+
+ appIdAuthManager.obtainAuthorization(Mockito.mock(Activity.class), new ResponseListener() {
+ @Override
+ public void onSuccess(Response response) {
+ fail("should get to onFailure");
+ }
+
+ @Override
+ public void onFailure(Response response, Throwable t, JSONObject extendedInfo) {
+ assertEquals(t.getMessage(), "Authorization canceled");
+ }
+ }, null);
+ }
+
}
diff --git a/lib/src/test/java/com/ibm/bluemix/appid/android/api/AppID_Test.java b/lib/src/test/java/com/ibm/bluemix/appid/android/api/AppID_Test.java
index 3676a9a..dcb38a0 100644
--- a/lib/src/test/java/com/ibm/bluemix/appid/android/api/AppID_Test.java
+++ b/lib/src/test/java/com/ibm/bluemix/appid/android/api/AppID_Test.java
@@ -127,5 +127,25 @@ public void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identi
appId.loginAnonymously(RuntimeEnvironment.application, "access_token", listener);
appId.loginAnonymously(RuntimeEnvironment.application, "access_token", false, listener);
}
+
+ @Test
+ public void test03_loginUsingRoP(){
+ this.appId.initialize(RuntimeEnvironment.application, testTenantId, testRegion);
+
+ TokenResponseListener listener = new TokenResponseListener() {
+ @Override
+ public void onAuthorizationFailure(AuthorizationException exception) {
+ assertThat(exception.getMessage().equals(RegistrationStatus.FAILED_TO_REGISTER.getDescription()));
+ }
+
+ @Override
+ public void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identityToken) {
+ assert(false);
+ }
+ };
+
+ appId.obtainTokensWithROP(RuntimeEnvironment.application, "testUsername", "testPassword", listener);
+
+ }
}
diff --git a/lib/src/test/java/com/ibm/bluemix/appid/android/internal/authorizationmanager/AuthorizationManager_Test.java b/lib/src/test/java/com/ibm/bluemix/appid/android/internal/authorizationmanager/AuthorizationManager_Test.java
new file mode 100644
index 0000000..789b4d9
--- /dev/null
+++ b/lib/src/test/java/com/ibm/bluemix/appid/android/internal/authorizationmanager/AuthorizationManager_Test.java
@@ -0,0 +1,383 @@
+/*
+ Copyright 2017 IBM Corp.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+package com.ibm.bluemix.appid.android.internal.authorizationmanager;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+import com.ibm.bluemix.appid.android.api.AppID;
+import com.ibm.bluemix.appid.android.api.AuthorizationException;
+import com.ibm.bluemix.appid.android.api.AuthorizationListener;
+import com.ibm.bluemix.appid.android.api.TokenResponseListener;
+import com.ibm.bluemix.appid.android.api.tokens.AccessToken;
+import com.ibm.bluemix.appid.android.api.tokens.IdentityToken;
+import com.ibm.bluemix.appid.android.internal.OAuthManager;
+import com.ibm.bluemix.appid.android.internal.network.AppIDRequest;
+import com.ibm.bluemix.appid.android.internal.network.AppIDRequestFactory;
+import com.ibm.bluemix.appid.android.internal.registrationmanager.RegistrationListener;
+import com.ibm.bluemix.appid.android.internal.registrationmanager.RegistrationManager;
+import com.ibm.bluemix.appid.android.internal.registrationmanager.RegistrationStatus;
+import com.ibm.bluemix.appid.android.internal.tokenmanager.TokenManager;
+import com.ibm.bluemix.appid.android.internal.tokens.AccessTokenImpl;
+import com.ibm.bluemix.appid.android.internal.tokens.IdentityTokenImpl;
+import com.ibm.bluemix.appid.android.testing.helpers.Consts;
+import com.ibm.mobilefirstplatform.appid_clientsdk_android.BuildConfig;
+import com.ibm.mobilefirstplatform.clientsdk.android.core.api.Response;
+import com.ibm.mobilefirstplatform.clientsdk.android.core.api.ResponseListener;
+
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.when;
+import static org.powermock.api.mockito.PowerMockito.doAnswer;
+
+@RunWith (RobolectricTestRunner.class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Config (constants = BuildConfig.class)
+public class AuthorizationManager_Test {
+
+ @Mock
+ private OAuthManager oAuthManagerMock;
+ @Mock
+ private RegistrationManager registrationManager;
+ @Mock
+ private TokenManager tokenManagerMock;
+ @Mock
+ private AppID appidMock;
+ @Mock
+ private PackageManager pmMock;
+ @Mock
+ private Context mockContext;
+ @Mock
+ private AppIDRequestFactory appIDRequestFactoryMock;
+ @Mock
+ private AppIDRequest mockRequest;
+ @Mock
+ private Activity mockActivity;
+ private AuthorizationManager authManager;
+ private String username = "testUser";
+ private String password = "testPassword";
+ private String testError = "Some Error";
+ private static final AccessToken expectedAccessToken = new AccessTokenImpl(Consts.ACCESS_TOKEN);
+ private static final IdentityToken expectedIdToken = new IdentityTokenImpl(Consts.ID_TOKEN);
+
+ private Response testResponse = new Response() {
+ @Override
+ public int getStatus() {
+ return 0;
+ }
+
+ @Override
+ public String getResponseText() {
+ return testError;
+ }
+
+ @Override
+ public byte[] getResponseBytes() {
+ return new byte[0];
+ }
+
+ @Override
+ public Map> getHeaders() {
+ Map> map = new HashMap>();
+ map.put("Location", new LinkedList());
+ return map;
+ }
+ };
+
+ @Before
+ public void before() {
+ MockitoAnnotations.initMocks(this);
+ when(oAuthManagerMock.getAppId()).thenReturn(appidMock);
+ when(oAuthManagerMock.getRegistrationManager()).thenReturn(registrationManager);
+ when(appidMock.getBluemixRegionSuffix()).thenReturn(".stubPrefix");
+ when(mockContext.getPackageManager()).thenReturn(pmMock);
+
+ when(oAuthManagerMock.getTokenManager()).thenReturn(tokenManagerMock);
+ doAnswer(new Answer() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ TokenResponseListener tokenListener = (TokenResponseListener) args[2];
+ tokenListener.onAuthorizationSuccess(expectedAccessToken, expectedIdToken);
+ return null;
+ }
+ }
+ ).when(tokenManagerMock).obtainTokens(eq(username), eq(password), any(TokenResponseListener.class));
+
+ doAnswer(new Answer() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ AuthorizationListener authListener = (AuthorizationListener) args[1];
+ authListener.onAuthorizationSuccess(expectedAccessToken, expectedIdToken);
+ return null;
+ }
+ }
+ ).when(tokenManagerMock).obtainTokens(anyString(), any(AuthorizationListener.class));
+
+ authManager = new AuthorizationManager(oAuthManagerMock, mockContext);
+ }
+
+ @Test
+ public void obtainTokensWithROP_registrationFailure() {
+
+ doAnswer(new Answer() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ RegistrationListener regListener = (RegistrationListener) args[1];
+ regListener.onRegistrationFailure(RegistrationStatus.NOT_REGISTRED);
+ return null;
+ }
+ }).when(registrationManager).ensureRegistered(eq(mockContext), any(RegistrationListener.class));
+
+
+ authManager.obtainTokensWithROP(mockContext, username, password, new TokenResponseListener() {
+ @Override
+ public void onAuthorizationFailure(AuthorizationException exception) {
+ assertEquals(exception.getMessage(), RegistrationStatus.NOT_REGISTRED.getDescription());
+ }
+
+ @Override
+ public void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identityToken) {
+ fail("should get to onAuthorizationFailure");
+ }
+ });
+ }
+
+ @Test
+ public void obtainTokensWithROP_registrationSuccess() {
+ doAnswer(new Answer() {
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ RegistrationListener regListener = (RegistrationListener) args[1];
+ regListener.onRegistrationSuccess();
+ return null;
+ }
+ }
+ ).when(registrationManager).ensureRegistered(eq(mockContext), any(RegistrationListener.class));
+
+ authManager.obtainTokensWithROP(mockContext, username, password, new TokenResponseListener() {
+ @Override
+ public void onAuthorizationFailure(AuthorizationException exception) {
+ fail("should get to onAuthorizationSuccess");
+ }
+
+ @Override
+ public void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identityToken) {
+ assertEquals(accessToken.getRaw(), expectedAccessToken.getRaw());
+ assertEquals(identityToken.getRaw(), expectedIdToken.getRaw());
+ }
+ });
+ }
+
+ @Test
+ public void loginAnonymously_success() {
+ doAnswer(new Answer() {
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ RegistrationListener regListener = (RegistrationListener) args[1];
+ regListener.onRegistrationSuccess();
+ return null;
+ }
+ }
+ ).when(registrationManager).ensureRegistered(eq(mockContext), any(RegistrationListener.class));
+
+ authManager.setAppIDRequestFactory(appIDRequestFactoryMock);
+ when(appIDRequestFactoryMock.createRequest(anyString(), anyString())).thenReturn(mockRequest);
+ doAnswer(new Answer() {
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ ResponseListener responseListener = (ResponseListener) args[0];
+ responseListener.onSuccess(testResponse);
+ return null;
+ }
+ }
+ ).when(mockRequest).send(any(ResponseListener.class));
+
+ authManager.loginAnonymously(mockContext, expectedAccessToken.getRaw(), true, new AuthorizationListener() {
+ @Override
+ public void onAuthorizationCanceled() {
+ fail("should get to onAuthorizationSuccess");
+ }
+
+ @Override
+ public void onAuthorizationFailure(AuthorizationException exception) {
+ fail("should get to onAuthorizationSuccess");
+ }
+
+ @Override
+ public void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identityToken) {
+ assertEquals(accessToken.getRaw(), expectedAccessToken.getRaw());
+ assertEquals(identityToken.getRaw(), expectedIdToken.getRaw());
+ }
+ });
+ }
+
+ @Test
+ public void loginAnonymously_failure() {
+ doAnswer(new Answer() {
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ RegistrationListener regListener = (RegistrationListener) args[1];
+ regListener.onRegistrationFailure(RegistrationStatus.NOT_REGISTRED);
+ return null;
+ }
+ }
+ ).when(registrationManager).ensureRegistered(eq(mockContext), any(RegistrationListener.class));
+
+
+ authManager.loginAnonymously(mockContext, expectedAccessToken.getRaw(), true, new AuthorizationListener() {
+ @Override
+ public void onAuthorizationCanceled() {
+ fail("should get to onAuthorizationFailure");
+ }
+
+ @Override
+ public void onAuthorizationFailure(AuthorizationException exception) {
+ assertEquals(exception.getMessage(), RegistrationStatus.NOT_REGISTRED.getDescription());
+ }
+
+ @Override
+ public void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identityToken) {
+ fail("should get to onAuthorizationFailure");
+ }
+ });
+ }
+
+ @Test
+ public void loginAnonymously_requestFailure() {
+ doAnswer(new Answer() {
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ RegistrationListener regListener = (RegistrationListener) args[1];
+ regListener.onRegistrationSuccess();
+ return null;
+ }
+ }
+ ).when(registrationManager).ensureRegistered(eq(mockContext), any(RegistrationListener.class));
+
+ authManager.setAppIDRequestFactory(appIDRequestFactoryMock);
+ when(appIDRequestFactoryMock.createRequest(anyString(), anyString())).thenReturn(mockRequest);
+ doAnswer(new Answer() {
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ ResponseListener responseListener = (ResponseListener) args[0];
+ responseListener.onFailure(null, new Throwable(testError), null);
+ return null;
+ }
+ }
+ ).when(mockRequest).send(any(ResponseListener.class));
+
+ authManager.loginAnonymously(mockContext, expectedAccessToken.getRaw(), true, new AuthorizationListener() {
+ @Override
+ public void onAuthorizationCanceled() {
+ fail("should get to onAuthorizationFailure");
+ }
+
+ @Override
+ public void onAuthorizationFailure(AuthorizationException exception) {
+ assertEquals(exception.getMessage(), testError);
+ }
+
+ @Override
+ public void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identityToken) {
+ fail("should get to onAuthorizationFailure");
+ }
+ });
+ }
+
+ @Test
+ public void launchAuthorizationUI_failure(){
+ Activity activity = new Activity();
+ doAnswer(new Answer() {
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ RegistrationListener regListener = (RegistrationListener) args[1];
+ regListener.onRegistrationFailure(RegistrationStatus.NOT_REGISTRED);
+ return null;
+ }
+ }
+ ).when(registrationManager).ensureRegistered(eq(activity), any(RegistrationListener.class));
+
+ authManager.launchAuthorizationUI(activity, new AuthorizationListener() {
+ @Override
+ public void onAuthorizationFailure(AuthorizationException exception) {
+ assertEquals(exception.getMessage(), RegistrationStatus.NOT_REGISTRED.getDescription());
+ }
+
+ @Override
+ public void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identityToken) {
+ fail("should get to onAuthorizationFailure");
+ }
+
+ @Override
+ public void onAuthorizationCanceled() {
+ fail("should get to onAuthorizationFailure");
+ }
+ });
+ }
+
+ @Test
+ public void launchAuthorizationUI_success(){
+
+ doAnswer(new Answer() {
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ RegistrationListener regListener = (RegistrationListener) args[1];
+ regListener.onRegistrationSuccess();
+ return null;
+ }
+ }
+ ).when(registrationManager).ensureRegistered(eq(mockActivity), any(RegistrationListener.class));
+
+ when(mockActivity.getApplicationContext()).thenReturn(mockContext);
+ authManager.launchAuthorizationUI(mockActivity, new AuthorizationListener() {
+ @Override
+ public void onAuthorizationFailure(AuthorizationException exception) {
+ assertEquals(exception.getMessage(), "Could NOT find installed browser that support Chrome tabs on the device.");
+ }
+
+ @Override
+ public void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identityToken) {
+ fail("should get to onAuthorizationFailure");
+ }
+
+ @Override
+ public void onAuthorizationCanceled() {
+ fail("should get to onAuthorizationFailure");
+ }
+ });
+ }
+}
diff --git a/lib/src/test/java/com/ibm/bluemix/appid/android/internal/authorizationmanager/AuthorizationUIManager_Test.java b/lib/src/test/java/com/ibm/bluemix/appid/android/internal/authorizationmanager/AuthorizationUIManager_Test.java
new file mode 100644
index 0000000..c18ca82
--- /dev/null
+++ b/lib/src/test/java/com/ibm/bluemix/appid/android/internal/authorizationmanager/AuthorizationUIManager_Test.java
@@ -0,0 +1,203 @@
+/*
+ Copyright 2017 IBM Corp.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+package com.ibm.bluemix.appid.android.internal.authorizationmanager;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+
+import com.ibm.bluemix.appid.android.api.AuthorizationException;
+import com.ibm.bluemix.appid.android.api.AuthorizationListener;
+import com.ibm.bluemix.appid.android.api.tokens.AccessToken;
+import com.ibm.bluemix.appid.android.api.tokens.IdentityToken;
+import com.ibm.bluemix.appid.android.internal.OAuthManager;
+
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.ibm.bluemix.appid.android.internal.authorizationmanager.AuthorizationUIManager.EXTRA_REDIRECT_URL;
+import static com.ibm.bluemix.appid.android.internal.authorizationmanager.AuthorizationUIManager.EXTRA_URL;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.when;
+
+@RunWith(RobolectricTestRunner.class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class AuthorizationUIManager_Test {
+
+ @Mock
+ private Context mockContext;
+ @Mock
+ private OAuthManager mockOAuthManager;
+ @Mock
+ private PackageManager pmMock;
+ @Mock
+ private ResolveInfo resolveInfoMock;
+ @Mock
+ private ResolveInfo resolveInfoMock2;
+ @Mock
+ private ActivityInfo activityInfoMock;
+ @Mock
+ private ActivityInfo activityInfoMock2;
+ @Mock
+ private Activity activityMock;
+
+ private AuthorizationListener authorizationListener;
+ private static final String STABLE_PACKAGE = "com.android.chrome";
+ private static final String BETA_PACKAGE = "com.chrome.beta";
+ private static final String DEV_PACKAGE = "com.chrome.dev";
+ private static final String LOCAL_PACKAGE = "com.google.android.apps.chrome";
+ private Intent spyIntent = Mockito.spy(new Intent());
+ private AuthorizationUIManager authorizationUIManager;
+ private AuthorizationUIManager authorizationUIManagerSpy;
+ private List resolveInfos;
+
+ @Before
+ public void before(){
+ MockitoAnnotations.initMocks(this);
+ when(mockContext.getPackageManager()).thenReturn(pmMock);
+ resolveInfos = new ArrayList<>();
+ resolveInfoMock.activityInfo = activityInfoMock;
+ activityInfoMock.packageName = "com.android.chrome_test";
+ resolveInfos.add(resolveInfoMock);
+ when(pmMock.queryIntentActivities(any(Intent.class), eq(0))).thenReturn(resolveInfos);
+ when(pmMock.resolveService(any(Intent.class), eq(0))).thenReturn(resolveInfoMock);
+ Mockito.doReturn(mockContext).when(activityMock).getApplicationContext();
+ authorizationListener = new AuthorizationListener() {
+ @Override
+ public void onAuthorizationCanceled() {
+ fail("should get to onAuthorizationFailure");
+ }
+
+ @Override
+ public void onAuthorizationFailure(AuthorizationException exception) {
+ assertEquals(exception.getMessage(), "Could NOT find installed browser that support Chrome tabs on the device.");
+ }
+
+ @Override
+ public void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identityToken) {
+ fail("should get to onAuthorizationFailure");
+ }
+ };
+ authorizationUIManager = new AuthorizationUIManager(mockOAuthManager, authorizationListener, "https://serverurlTest", "https://redirectTest");
+ authorizationUIManagerSpy = Mockito.spy(authorizationUIManager);
+ Mockito.doReturn(spyIntent).when(authorizationUIManagerSpy).createChromeTabIntent(activityMock);
+ resolveInfoMock2.activityInfo = activityInfoMock2;
+
+ }
+
+ @Test
+ public void launch_test() {
+ Mockito.reset(spyIntent);
+ authorizationUIManagerSpy.launch(activityMock);
+ Mockito.verify(spyIntent).putExtra(EXTRA_REDIRECT_URL, "https://redirectTest");
+ Mockito.verify(spyIntent).putExtra(EXTRA_URL, "https://serverurlTest");
+
+ }
+
+ @Test
+ public void launch_test_LOCAL_PACKAGE() {
+ Mockito.reset(spyIntent);
+ activityInfoMock2.packageName = LOCAL_PACKAGE;
+ resolveInfos.add(resolveInfoMock2);
+ authorizationUIManagerSpy.reset_sPackageNameToUse();
+ authorizationUIManagerSpy.launch(activityMock);
+ Mockito.verify(spyIntent).putExtra(EXTRA_REDIRECT_URL, "https://redirectTest");
+ Mockito.verify(spyIntent).putExtra(EXTRA_URL, "https://serverurlTest");
+
+ }
+
+ @Test
+ public void launch_test_DEV_PACKAGE() {
+ Mockito.reset(spyIntent);
+ activityInfoMock2.packageName = DEV_PACKAGE;
+ resolveInfos.add(resolveInfoMock2);
+ authorizationUIManagerSpy.reset_sPackageNameToUse();
+ authorizationUIManagerSpy.launch(activityMock);
+ Mockito.verify(spyIntent).putExtra(EXTRA_REDIRECT_URL, "https://redirectTest");
+ Mockito.verify(spyIntent).putExtra(EXTRA_URL, "https://serverurlTest");
+
+ }
+ @Test
+ public void launch_test_BETA_PACKAGE() {
+ Mockito.reset(spyIntent);
+ activityInfoMock2.packageName = BETA_PACKAGE;
+ resolveInfos.add(resolveInfoMock2);
+ authorizationUIManagerSpy.reset_sPackageNameToUse();
+ authorizationUIManagerSpy.launch(activityMock);
+ Mockito.verify(spyIntent).putExtra(EXTRA_REDIRECT_URL, "https://redirectTest");
+ Mockito.verify(spyIntent).putExtra(EXTRA_URL, "https://serverurlTest");
+
+ }
+ @Test
+ public void launch_test_STABLE_PACKAGE() {
+ Mockito.reset(spyIntent);
+ activityInfoMock2.packageName = STABLE_PACKAGE;
+ resolveInfos.add(resolveInfoMock2);
+ authorizationUIManagerSpy.reset_sPackageNameToUse();
+ authorizationUIManagerSpy.launch(activityMock);
+ Mockito.verify(spyIntent).putExtra(EXTRA_REDIRECT_URL, "https://redirectTest");
+ Mockito.verify(spyIntent).putExtra(EXTRA_URL, "https://serverurlTest");
+
+ }
+
+ @Test
+ public void launch_test_hasSpecializedHandlerIntents_test() {
+ Mockito.reset(spyIntent);
+ authorizationUIManagerSpy.reset_sPackageNameToUse();
+ activityInfoMock2.packageName = STABLE_PACKAGE;
+ resolveInfos.add(resolveInfoMock2);
+ when(pmMock.resolveActivity(any(Intent.class), eq(0))).thenReturn(resolveInfoMock);
+
+ authorizationUIManagerSpy.launch(activityMock);
+ Mockito.verify(spyIntent).putExtra(EXTRA_REDIRECT_URL, "https://redirectTest");
+ Mockito.verify(spyIntent).putExtra(EXTRA_URL, "https://serverurlTest");
+
+ }
+
+ @Test
+ public void launch_test_hasSpecializedHandlerIntents_return_true() {
+ authorizationUIManagerSpy.reset_sPackageNameToUse();
+ activityInfoMock2.packageName = STABLE_PACKAGE;
+ resolveInfos.add(resolveInfoMock2);
+ IntentFilter mockFilter = Mockito.mock(IntentFilter.class);
+ resolveInfoMock2.filter = mockFilter;
+ resolveInfoMock2.activityInfo = Mockito.mock(ActivityInfo.class);
+ when(mockFilter.countDataAuthorities()).thenReturn(3);
+ when(mockFilter.countDataPaths()).thenReturn(3);
+
+ when(pmMock.resolveActivity(any(Intent.class), eq(0))).thenReturn(resolveInfoMock);
+
+ when(pmMock.queryIntentActivities(any(Intent.class), eq(PackageManager.GET_RESOLVED_FILTER))).thenReturn(resolveInfos);
+
+ authorizationUIManagerSpy.launch(activityMock);
+
+
+ }
+}
diff --git a/lib/src/test/java/com/ibm/bluemix/appid/android/internal/loginwidget/LoginWidgetImpl_Test.java b/lib/src/test/java/com/ibm/bluemix/appid/android/internal/loginwidget/LoginWidgetImpl_Test.java
new file mode 100644
index 0000000..44a2021
--- /dev/null
+++ b/lib/src/test/java/com/ibm/bluemix/appid/android/internal/loginwidget/LoginWidgetImpl_Test.java
@@ -0,0 +1,132 @@
+/*
+ Copyright 2017 IBM Corp.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+package com.ibm.bluemix.appid.android.internal.loginwidget;
+
+import android.app.Activity;
+
+import com.ibm.bluemix.appid.android.api.AuthorizationException;
+import com.ibm.bluemix.appid.android.api.AuthorizationListener;
+import com.ibm.bluemix.appid.android.api.tokens.AccessToken;
+import com.ibm.bluemix.appid.android.api.tokens.IdentityToken;
+import com.ibm.bluemix.appid.android.internal.OAuthManager;
+import com.ibm.bluemix.appid.android.internal.authorizationmanager.AuthorizationManager;
+import com.ibm.bluemix.appid.android.internal.tokenmanager.TokenManager;
+import com.ibm.bluemix.appid.android.internal.tokens.AccessTokenImpl;
+import com.ibm.bluemix.appid.android.testing.helpers.Consts;
+
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.robolectric.RobolectricTestRunner;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
+
+@RunWith(RobolectricTestRunner.class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class LoginWidgetImpl_Test {
+
+ @Mock
+ private OAuthManager oAuthManager;
+ @Mock
+ private AuthorizationManager mockAuthManager;
+ @Mock
+ private TokenManager mockTokenManager;
+
+ private static final AccessToken expectedAccessToken = new AccessTokenImpl(Consts.ACCESS_TOKEN);
+ private LoginWidgetImpl loginWidget;
+ @Before
+ public void before(){
+ MockitoAnnotations.initMocks(this);
+ loginWidget = new LoginWidgetImpl(oAuthManager);
+ when(oAuthManager.getAuthorizationManager()).thenReturn(mockAuthManager);
+ when(oAuthManager.getTokenManager()).thenReturn(mockTokenManager);
+ when(mockTokenManager.getLatestAccessToken()).thenReturn(expectedAccessToken);
+ }
+
+ @Test
+ public void launch_test(){
+
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ AccessToken accessToken = (AccessToken) args[1];
+ AuthorizationListener authorizationListener = (AuthorizationListener) args[2];
+ authorizationListener.onAuthorizationSuccess(accessToken, null);
+ return null;
+ }
+ }).when(mockAuthManager).launchAuthorizationUI(any(Activity.class), any(AccessToken.class),any(AuthorizationListener.class));
+
+
+ loginWidget.launch(Mockito.mock(Activity.class), new AuthorizationListener() {
+ @Override
+ public void onAuthorizationCanceled() {
+ fail("should get to onAuthorizationSuccess");
+ }
+
+ @Override
+ public void onAuthorizationFailure(AuthorizationException exception) {
+ fail("should get to onAuthorizationSuccess");
+ }
+
+ @Override
+ public void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identityToken) {
+ assertEquals(accessToken, expectedAccessToken);
+ }
+ }, null);
+ }
+
+ @Test
+ public void launch_test_with_access_token(){
+
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ AccessToken accessToken = (AccessToken) args[1];
+ AuthorizationListener authorizationListener = (AuthorizationListener) args[2];
+ authorizationListener.onAuthorizationSuccess(accessToken, null);
+ return null;
+ }
+ }).when(mockAuthManager).launchAuthorizationUI(any(Activity.class), any(AccessToken.class),any(AuthorizationListener.class));
+
+
+ loginWidget.launch(Mockito.mock(Activity.class), new AuthorizationListener() {
+ @Override
+ public void onAuthorizationCanceled() {
+ fail("should get to onAuthorizationSuccess");
+ }
+
+ @Override
+ public void onAuthorizationFailure(AuthorizationException exception) {
+ fail("should get to onAuthorizationSuccess");
+ }
+
+ @Override
+ public void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identityToken) {
+ assertEquals(accessToken.getRaw(), expectedAccessToken.getRaw());
+ }
+ }, expectedAccessToken.getRaw());
+ }
+}
diff --git a/lib/src/test/java/com/ibm/bluemix/appid/android/internal/network/AppIDRequestFactory_Test.java b/lib/src/test/java/com/ibm/bluemix/appid/android/internal/network/AppIDRequestFactory_Test.java
new file mode 100644
index 0000000..00c075a
--- /dev/null
+++ b/lib/src/test/java/com/ibm/bluemix/appid/android/internal/network/AppIDRequestFactory_Test.java
@@ -0,0 +1,30 @@
+/*
+ Copyright 2017 IBM Corp.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+package com.ibm.bluemix.appid.android.internal.network;
+
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+
+public class AppIDRequestFactory_Test {
+
+ private String testUrl = "testUrl";
+ private String testMethod = "testMethod";
+ @Test
+ public void createRequest_test() {
+ AppIDRequestFactory appIDRequestFactory = new AppIDRequestFactory();
+ AppIDRequest appIDRequest = appIDRequestFactory.createRequest(testUrl, testMethod);
+ assertEquals(appIDRequest.getMethod(), testMethod);
+ assertEquals(appIDRequest.getUrl(), testUrl);
+ }
+}
diff --git a/lib/src/test/java/com/ibm/bluemix/appid/android/internal/network/AppIDRequest_Test.java b/lib/src/test/java/com/ibm/bluemix/appid/android/internal/network/AppIDRequest_Test.java
new file mode 100644
index 0000000..e2fe9ee
--- /dev/null
+++ b/lib/src/test/java/com/ibm/bluemix/appid/android/internal/network/AppIDRequest_Test.java
@@ -0,0 +1,124 @@
+/*
+ Copyright 2017 IBM Corp.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+package com.ibm.bluemix.appid.android.internal.network;
+
+import com.ibm.bluemix.appid.android.api.tokens.AccessToken;
+import com.ibm.bluemix.appid.android.internal.tokens.AccessTokenImpl;
+import com.ibm.bluemix.appid.android.testing.helpers.Consts;
+import com.ibm.mobilefirstplatform.clientsdk.android.core.api.Response;
+import com.ibm.mobilefirstplatform.clientsdk.android.core.api.ResponseListener;
+
+import org.json.JSONObject;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.robolectric.RobolectricTestRunner;
+import java.util.List;
+import java.util.Map;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+
+@RunWith(RobolectricTestRunner.class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class AppIDRequest_Test {
+
+ AppIDRequestFactory appIDRequestFactory = new AppIDRequestFactory();
+ AppIDRequest appIDRequest = appIDRequestFactory.createRequest("testUrl", "testMethod");
+ AppIDRequest spyAppIDRequest = Mockito.spy(appIDRequest);
+ private static final AccessToken expectedAccessToken = new AccessTokenImpl(Consts.ACCESS_TOKEN);
+
+ @Test
+ public void send_test(){
+
+ Mockito.doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ String header = (String) args[0];
+ if (!header.equals("Authorization")) {
+ fail("header is not Authorization");
+ }
+ return null;
+ }
+ }).when(spyAppIDRequest).removeHeaders(anyString());
+
+ Mockito.doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ String header = (String) args[0];
+ String bearerPlusToken = (String) args[1];
+ if (!header.equals("Authorization")) {
+ fail("header is not Authorization");
+ }
+ if (!bearerPlusToken.equals("Bearer " + expectedAccessToken.getRaw())) {
+ fail("addHeader params mismatch");
+ }
+ return null;
+ }
+ }).when(spyAppIDRequest).addHeader(anyString(),anyString());
+
+
+ final Response testReponse = new Response() {
+ @Override
+ public int getStatus() {
+ return 200;
+ }
+
+ @Override
+ public String getResponseText() {
+ return null;
+ }
+
+ @Override
+ public byte[] getResponseBytes() {
+ return new byte[0];
+ }
+
+ @Override
+ public Map> getHeaders() {
+ return null;
+ }
+ };
+
+ Mockito.doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ResponseListener responseListener = (ResponseListener) args[0];
+ responseListener.onSuccess(testReponse);
+ return null;
+ }
+ }).when(spyAppIDRequest).send(any(ResponseListener.class));
+
+
+ spyAppIDRequest.send(new ResponseListener() {
+ @Override
+ public void onSuccess(Response response) {
+ assertEquals(response.getStatus(), 200);
+ }
+
+ @Override
+ public void onFailure(Response response, Throwable t, JSONObject extendedInfo) {
+ fail("should get to onSuccess");
+ }
+ }, null, expectedAccessToken);
+ }
+}
diff --git a/lib/src/test/java/com/ibm/bluemix/appid/android/internal/tokenmanager/TokenManager_Test.java b/lib/src/test/java/com/ibm/bluemix/appid/android/internal/tokenmanager/TokenManager_Test.java
new file mode 100644
index 0000000..f664a44
--- /dev/null
+++ b/lib/src/test/java/com/ibm/bluemix/appid/android/internal/tokenmanager/TokenManager_Test.java
@@ -0,0 +1,451 @@
+/*
+ Copyright 2017 IBM Corp.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+package com.ibm.bluemix.appid.android.internal.tokenmanager;
+
+import com.ibm.bluemix.appid.android.api.AppID;
+import com.ibm.bluemix.appid.android.api.AuthorizationException;
+import com.ibm.bluemix.appid.android.api.AuthorizationListener;
+import com.ibm.bluemix.appid.android.api.TokenResponseListener;
+import com.ibm.bluemix.appid.android.api.tokens.AccessToken;
+import com.ibm.bluemix.appid.android.api.tokens.IdentityToken;
+import com.ibm.bluemix.appid.android.internal.OAuthManager;
+import com.ibm.bluemix.appid.android.internal.network.AppIDRequest;
+import com.ibm.bluemix.appid.android.internal.preferences.JSONPreference;
+import com.ibm.bluemix.appid.android.internal.preferences.PreferenceManager;
+import com.ibm.bluemix.appid.android.internal.registrationmanager.RegistrationManager;
+import com.ibm.bluemix.appid.android.internal.tokens.AccessTokenImpl;
+import com.ibm.bluemix.appid.android.internal.tokens.IdentityTokenImpl;
+import com.ibm.bluemix.appid.android.testing.helpers.Consts;
+import com.ibm.mobilefirstplatform.clientsdk.android.core.api.Response;
+import com.ibm.mobilefirstplatform.clientsdk.android.core.api.ResponseListener;
+
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.robolectric.RobolectricTestRunner;
+
+import java.math.BigInteger;
+import java.security.Signature;
+import java.security.interfaces.RSAPrivateKey;
+import java.util.List;
+import java.util.Map;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
+
+@RunWith(RobolectricTestRunner.class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class TokenManager_Test {
+
+ @Mock
+ private PreferenceManager pmMock;
+ @Mock
+ private OAuthManager oAuthManagerMock;
+ @Mock
+ private AppID appidMock;
+ @Mock
+ private AppIDRequest stubRequest;
+ @Mock
+ private JSONPreference JSONPreferenceMock;
+
+ private TokenManager spyTokenManager;
+ private String username = "testUser";
+ private String password = "testPassword";
+ private String stubClientId = "00001111-1111-1111-1111-123456789012";
+ private String stubRedirectUri = "http://stub";
+ private static final AccessToken expectedAccessToken = new AccessTokenImpl(Consts.ACCESS_TOKEN);
+ private static final IdentityToken expectedIdToken = new IdentityTokenImpl(Consts.ID_TOKEN);
+ private Response testReponse;
+
+ @Before
+ public void before() {
+ MockitoAnnotations.initMocks(this);
+ when(oAuthManagerMock.getAppId()).thenReturn(appidMock);
+ when(oAuthManagerMock.getPreferenceManager()).thenReturn(pmMock);
+ RegistrationManager registrationManager = new RegistrationManager(oAuthManagerMock);
+ RegistrationManager spyRm = Mockito.spy(registrationManager);
+ doReturn(stubClientId).when(spyRm).getRegistrationDataString(anyString());
+ doReturn(stubRedirectUri).when(spyRm).getRegistrationDataString(anyString(), eq(0));
+ doReturn(new RSAPrivateKey() {
+ @Override
+ public BigInteger getPrivateExponent() {
+ return new BigInteger("57791d5430d593164082036ad8b29fb157791d5430d593164082036ad8b29fb157791d5430d593164082036ad8b29fb157791d5430d593164082036ad8b29fb1", 16);
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return "RSA256";
+ }
+
+ @Override
+ public String getFormat() {
+ return "UTF8";
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return new byte[0];
+ }
+
+ @Override
+ public BigInteger getModulus() {
+ return new BigInteger("57791d5430d593164082036ad8b29fb157791d5430d593164082036ad8b29fb157791d5430d593164082036ad8b29fb157791d5430d593164082036ad8b29fb1", 16);
+ }
+ }).when(spyRm).getPrivateKey();
+ when(oAuthManagerMock.getRegistrationManager()).thenReturn(spyRm);
+ TokenManager tokenManager = new TokenManager(oAuthManagerMock);
+ spyTokenManager = Mockito.spy(tokenManager);
+ when(spyTokenManager.createAppIDRequest(anyString(), anyString())).thenReturn(stubRequest);
+ doNothing().when(stubRequest).addHeader(anyString(), anyString());
+ }
+
+ @Test
+ public void obtainTokensRop_success() {
+
+ testReponse = new Response() {
+ @Override
+ public int getStatus() {
+ return 200;
+ }
+
+ @Override
+ public String getResponseText() {
+ return "{\"access_token\": " + expectedAccessToken.getRaw() +", " +
+ "\"id_token\":" + expectedIdToken.getRaw() + "}";
+ }
+
+ @Override
+ public byte[] getResponseBytes() {
+ return new byte[0];
+ }
+
+ @Override
+ public Map> getHeaders() {
+ return null;
+ }
+ };
+
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ResponseListener responseListener = (ResponseListener) args[1];
+ responseListener.onSuccess(testReponse);
+ return null;
+ }
+ }).when(stubRequest).send(any(Map.class), any(ResponseListener.class));
+
+ spyTokenManager.obtainTokens(username, password, new TokenResponseListener() {
+ @Override
+ public void onAuthorizationFailure(AuthorizationException exception) {
+ fail("should get to onAuthorizationSuccess");
+ }
+
+ @Override
+ public void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identityToken) {
+ assertEquals(accessToken.getRaw(), expectedAccessToken.getRaw());
+ assertEquals(identityToken.getRaw(), expectedIdToken.getRaw());
+ }
+ });
+ }
+
+ @Test
+ public void obtainTokensRop_failure() {
+
+ final String testDescription = "test description error123";
+ testReponse = new Response() {
+ @Override
+ public int getStatus() {
+ return 400;
+ }
+
+ @Override
+ public String getResponseText() {
+ return "{\"error\": \"invalid_grant\" , \"error_description\": \"" + testDescription + "\" }";
+ }
+
+ @Override
+ public byte[] getResponseBytes() {
+ return new byte[0];
+ }
+
+ @Override
+ public Map> getHeaders() {
+ return null;
+ }
+ };
+
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ResponseListener responseListener = (ResponseListener) args[1];
+ responseListener.onFailure(testReponse ,null, null);
+ return null;
+ }
+ }).when(stubRequest).send(any(Map.class), any(ResponseListener.class));
+
+ spyTokenManager.obtainTokens(username, password, new TokenResponseListener() {
+ @Override
+ public void onAuthorizationFailure(AuthorizationException exception) {
+ assertEquals(exception.getMessage(), "Failed to retrieve tokens: " + testDescription);
+ }
+
+ @Override
+ public void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identityToken) {
+ fail("should get to onAuthorizationFailure");
+
+ }
+ });
+ //test the exception parsing
+ testReponse = null;
+ spyTokenManager.obtainTokens(username, password, new TokenResponseListener() {
+ @Override
+ public void onAuthorizationFailure(AuthorizationException exception) {
+ assertEquals(exception.getMessage(), "Failed to retrieve tokens" );
+ }
+
+ @Override
+ public void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identityToken) {
+ fail("should get to onAuthorizationFailure");
+
+ }
+ });
+ }
+
+ @Test
+ public void obtainTokensRop_failures_in_parsing_response() {
+ //bad response
+ testReponse = null;
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ResponseListener responseListener = (ResponseListener) args[1];
+ responseListener.onSuccess(testReponse);
+ return null;
+ }
+ }).when(stubRequest).send(any(Map.class), any(ResponseListener.class));
+
+ spyTokenManager.obtainTokens(username, password, new TokenResponseListener() {
+ @Override
+ public void onAuthorizationFailure(AuthorizationException exception) {
+ assertEquals(exception.getMessage(), "Failed to parse server response");
+ }
+
+ @Override
+ public void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identityToken) {
+ fail("should get to onAuthorizationFailure");
+
+ }
+ });
+ //bad access token
+ testReponse = new Response() {
+ @Override
+ public int getStatus() {
+ return 200;
+ }
+
+ @Override
+ public String getResponseText() {
+ return "{\"access_token\": " + "\"bad access token\"" + ", " +
+ "\"id_token\":" + expectedIdToken.getRaw() + "}";
+ }
+
+ @Override
+ public byte[] getResponseBytes() {
+ return new byte[0];
+ }
+
+ @Override
+ public Map> getHeaders() {
+ return null;
+ }
+ };
+ spyTokenManager.obtainTokens(username, password, new TokenResponseListener() {
+ @Override
+ public void onAuthorizationFailure(AuthorizationException exception) {
+ assertEquals(exception.getMessage(), "Failed to parse access_token");
+ }
+
+ @Override
+ public void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identityToken) {
+ fail("should get to onAuthorizationFailure");
+
+ }
+ });
+ //bad id token
+ testReponse = new Response() {
+ @Override
+ public int getStatus() {
+ return 200;
+ }
+
+ @Override
+ public String getResponseText() {
+ return "{\"access_token\": " + expectedAccessToken.getRaw() + ", " +
+ "\"id_token\":" + "\"bad Id token\"" + "}";
+ }
+
+ @Override
+ public byte[] getResponseBytes() {
+ return new byte[0];
+ }
+
+ @Override
+ public Map> getHeaders() {
+ return null;
+ }
+ };
+
+ spyTokenManager.obtainTokens(username, password, new TokenResponseListener() {
+ @Override
+ public void onAuthorizationFailure(AuthorizationException exception) {
+ assertEquals(exception.getMessage(), "Failed to parse id_token");
+ }
+
+ @Override
+ public void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identityToken) {
+ fail("should get to onAuthorizationFailure");
+
+ }
+ });
+ }
+
+
+
+ @Test
+ public void obtainTokens_Authorization_Code_success() {
+
+ testReponse = new Response() {
+ @Override
+ public int getStatus() {
+ return 200;
+ }
+
+ @Override
+ public String getResponseText() {
+ return "{\"access_token\": " + expectedAccessToken.getRaw() +", " +
+ "\"id_token\":" + expectedIdToken.getRaw() + "}";
+ }
+
+ @Override
+ public byte[] getResponseBytes() {
+ return new byte[0];
+ }
+
+ @Override
+ public Map> getHeaders() {
+ return null;
+ }
+ };
+
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ResponseListener responseListener = (ResponseListener) args[1];
+ responseListener.onSuccess(testReponse);
+ return null;
+ }
+ }).when(stubRequest).send(any(Map.class), any(ResponseListener.class));
+
+ spyTokenManager.obtainTokens("Some Code", new AuthorizationListener() {
+ @Override
+ public void onAuthorizationCanceled() {
+ fail("should get to onAuthorizationSuccess");
+ }
+
+ @Override
+ public void onAuthorizationFailure(AuthorizationException exception) {
+ fail("should get to onAuthorizationSuccess");
+ }
+
+ @Override
+ public void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identityToken) {
+ assertEquals(accessToken.getRaw(), expectedAccessToken.getRaw());
+ assertEquals(identityToken.getRaw(), expectedIdToken.getRaw());
+ }
+ });
+ }
+
+ @Test
+ public void obtainTokens_Authorization_Code_failure() {
+
+ testReponse = new Response() {
+ @Override
+ public int getStatus() {
+ return 200;
+ }
+
+ @Override
+ public String getResponseText() {
+ return "{\"access_token\": " + expectedAccessToken.getRaw() +", " +
+ "\"id_token\":" + expectedIdToken.getRaw() + "}";
+ }
+
+ @Override
+ public byte[] getResponseBytes() {
+ return new byte[0];
+ }
+
+ @Override
+ public Map> getHeaders() {
+ return null;
+ }
+ };
+
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ResponseListener responseListener = (ResponseListener) args[1];
+ responseListener.onFailure(null, null, null);
+ return null;
+ }
+ }).when(stubRequest).send(any(Map.class), any(ResponseListener.class));
+
+ spyTokenManager.obtainTokens("Some Code", new AuthorizationListener() {
+ @Override
+ public void onAuthorizationCanceled() {
+ fail("should get to onAuthorizationFailure");
+ }
+
+ @Override
+ public void onAuthorizationFailure(AuthorizationException exception) {
+ assertEquals(exception.getMessage(), "Failed to retrieve tokens");
+ }
+
+ @Override
+ public void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identityToken) {
+ fail("should get to onAuthorizationFailure");
+
+ }
+ });
+ }
+}
diff --git a/lib/src/test/java/com/ibm/bluemix/appid/android/internal/userattributesmanager/UserAttributeManagerImpl_Test.java b/lib/src/test/java/com/ibm/bluemix/appid/android/internal/userattributesmanager/UserAttributeManagerImpl_Test.java
new file mode 100644
index 0000000..ecaf5ef
--- /dev/null
+++ b/lib/src/test/java/com/ibm/bluemix/appid/android/internal/userattributesmanager/UserAttributeManagerImpl_Test.java
@@ -0,0 +1,684 @@
+/*
+ Copyright 2017 IBM Corp.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+package com.ibm.bluemix.appid.android.internal.userattributesmanager;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+import com.ibm.bluemix.appid.android.api.AppID;
+import com.ibm.bluemix.appid.android.api.tokens.AccessToken;
+import com.ibm.bluemix.appid.android.api.userattributes.UserAttributeResponseListener;
+import com.ibm.bluemix.appid.android.api.userattributes.UserAttributesException;
+import com.ibm.bluemix.appid.android.internal.network.AppIDRequest;
+import com.ibm.bluemix.appid.android.internal.tokenmanager.TokenManager;
+import com.ibm.bluemix.appid.android.internal.tokens.AccessTokenImpl;
+import com.ibm.bluemix.appid.android.testing.helpers.Consts;
+import com.ibm.mobilefirstplatform.clientsdk.android.core.api.Response;
+import com.ibm.mobilefirstplatform.clientsdk.android.core.api.ResponseListener;
+import com.squareup.okhttp.RequestBody;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.robolectric.RobolectricTestRunner;
+
+import java.util.List;
+import java.util.Map;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
+
+@RunWith(RobolectricTestRunner.class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class UserAttributeManagerImpl_Test {
+
+ @Mock
+ private RequestBody stubRequestBody;
+ @Mock
+ private AppIDRequest stubRequest;
+ @Mock
+ private AppIDRequest specificStubRequest;
+ @Mock
+ private TokenManager tokenManagerMock;
+ @Mock
+ private Context mockContext;
+ @Mock
+ private PackageManager pmMock;
+
+ private UserAttributeManagerImpl userAttributeManagerSpy;
+ private static final AccessToken expectedAccessToken = new AccessTokenImpl(Consts.ACCESS_TOKEN);
+
+ @Before
+ public void before(){
+ MockitoAnnotations.initMocks(this);
+ UserAttributeManagerImpl userAttributeManager = new UserAttributeManagerImpl(tokenManagerMock);
+ when(tokenManagerMock.getLatestAccessToken()).thenReturn(expectedAccessToken);
+ userAttributeManagerSpy = Mockito.spy(userAttributeManager);
+ Mockito.doReturn(stubRequest).when(userAttributeManagerSpy).createAppIDRequest(anyString(), anyString());
+ when(mockContext.getApplicationContext()).thenReturn(mockContext);
+ when(mockContext.getPackageManager()).thenReturn(pmMock);
+ AppID.getInstance().initialize(mockContext,"00001111-1111-1111-1111-123456789012",".test");
+ }
+
+ @Test
+ public void getAllAttributes_happy_flow() {
+
+ final Response testReponse = new Response() {
+ @Override
+ public int getStatus() {
+ return 200;
+ }
+
+ @Override
+ public String getResponseText() {
+ return "{\"age\": 30, \"email\":\"test@ibm.com\"}";
+ }
+
+ @Override
+ public byte[] getResponseBytes() {
+ return new byte[0];
+ }
+
+ @Override
+ public Map> getHeaders() {
+ return null;
+ }
+ };
+
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ResponseListener responseListener = (ResponseListener) args[0];
+ responseListener.onSuccess(testReponse);
+ return null;
+ }
+ }).when(stubRequest).send(any(ResponseListener.class), any(RequestBody.class), eq(expectedAccessToken));
+
+ userAttributeManagerSpy.getAllAttributes(expectedAccessToken, new UserAttributeResponseListener() {
+ @Override
+ public void onSuccess(JSONObject attributes) {
+ try {
+ assertEquals(attributes.getInt("age"), 30);
+ assertEquals(attributes.getString("email"), "test@ibm.com");
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ @Override
+ public void onFailure(UserAttributesException e) {
+ fail("should get to onSuccess");
+ }
+ });
+
+ }
+
+ @Test
+ public void getAllAttributes_happy_flow_null_response_text() {
+
+ final Response testReponse = new Response() {
+ @Override
+ public int getStatus() {
+ return 200;
+ }
+
+ @Override
+ public String getResponseText() {
+ return null;
+ }
+
+ @Override
+ public byte[] getResponseBytes() {
+ return new byte[0];
+ }
+
+ @Override
+ public Map> getHeaders() {
+ return null;
+ }
+ };
+
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ResponseListener responseListener = (ResponseListener) args[0];
+ responseListener.onSuccess(testReponse);
+ return null;
+ }
+ }).when(stubRequest).send(any(ResponseListener.class), any(RequestBody.class), eq(expectedAccessToken));
+
+ userAttributeManagerSpy.getAllAttributes(expectedAccessToken, new UserAttributeResponseListener() {
+ @Override
+ public void onSuccess(JSONObject attributes) {
+ assertEquals(attributes.toString(), "{}");
+ }
+
+ @Override
+ public void onFailure(UserAttributesException e) {
+ fail("should get to onSuccess");
+ }
+ });
+
+ }
+
+ @Test
+ public void getAllAttributes_happy_flow_empty_response_text() {
+
+ final Response testReponse = new Response() {
+ @Override
+ public int getStatus() {
+ return 200;
+ }
+
+ @Override
+ public String getResponseText() {
+ return "";
+ }
+
+ @Override
+ public byte[] getResponseBytes() {
+ return new byte[0];
+ }
+
+ @Override
+ public Map> getHeaders() {
+ return null;
+ }
+ };
+
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ResponseListener responseListener = (ResponseListener) args[0];
+ responseListener.onSuccess(testReponse);
+ return null;
+ }
+ }).when(stubRequest).send(any(ResponseListener.class), any(RequestBody.class), eq(expectedAccessToken));
+
+ userAttributeManagerSpy.getAllAttributes(expectedAccessToken, new UserAttributeResponseListener() {
+ @Override
+ public void onSuccess(JSONObject attributes) {
+ assertEquals(attributes.toString(), "{}");
+ }
+
+ @Override
+ public void onFailure(UserAttributesException e) {
+ fail("should get to onSuccess");
+ }
+ });
+
+ }
+
+ @Test
+ public void getAllAttributes_request_failure_json_format() {
+
+ final Response testReponse = new Response() {
+ @Override
+ public int getStatus() {
+ return 200;
+ }
+
+ @Override
+ public String getResponseText() {
+ return "56";
+ }
+
+ @Override
+ public byte[] getResponseBytes() {
+ return new byte[0];
+ }
+
+ @Override
+ public Map> getHeaders() {
+ return null;
+ }
+ };
+
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ResponseListener responseListener = (ResponseListener) args[0];
+ responseListener.onSuccess(testReponse);
+ return null;
+ }
+ }).when(stubRequest).send(any(ResponseListener.class), any(RequestBody.class), eq(expectedAccessToken));
+
+ userAttributeManagerSpy.getAllAttributes(expectedAccessToken, new UserAttributeResponseListener() {
+ @Override
+ public void onSuccess(JSONObject attributes) {
+ fail("should get to onFailure");
+
+ }
+
+ @Override
+ public void onFailure(UserAttributesException e) {
+ assertEquals(e.getError(), UserAttributesException.Error.JSON_PARSE_ERROR);
+ }
+ });
+ }
+
+ @Test
+ public void getAllAttributes_request_failure() {
+
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ResponseListener responseListener = (ResponseListener) args[0];
+ responseListener.onFailure(null, null, null);
+ return null;
+ }
+ }).when(stubRequest).send(any(ResponseListener.class), any(RequestBody.class), eq(expectedAccessToken));
+
+ userAttributeManagerSpy.getAllAttributes(expectedAccessToken, new UserAttributeResponseListener() {
+ @Override
+ public void onSuccess(JSONObject attributes) {
+ fail("should get to onFailure");
+
+ }
+
+ @Override
+ public void onFailure(UserAttributesException e) {
+ assertEquals(e.getError(), UserAttributesException.Error.FAILED_TO_CONNECT);
+ }
+ });
+ }
+
+ @Test
+ public void getAllAttributes_request_failure_401() {
+ final Response testReponse = new Response() {
+ @Override
+ public int getStatus() {
+ return 401;
+ }
+
+ @Override
+ public String getResponseText() {
+ return null;
+ }
+
+ @Override
+ public byte[] getResponseBytes() {
+ return new byte[0];
+ }
+
+ @Override
+ public Map> getHeaders() {
+ return null;
+ }
+ };
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ResponseListener responseListener = (ResponseListener) args[0];
+ responseListener.onFailure(testReponse, null, null);
+ return null;
+ }
+ }).when(stubRequest).send(any(ResponseListener.class), any(RequestBody.class), eq(expectedAccessToken));
+
+ userAttributeManagerSpy.getAllAttributes(expectedAccessToken, new UserAttributeResponseListener() {
+ @Override
+ public void onSuccess(JSONObject attributes) {
+ fail("should get to onFailure");
+
+ }
+
+ @Override
+ public void onFailure(UserAttributesException e) {
+ assertEquals(e.getError(), UserAttributesException.Error.UNAUTHORIZED);
+ }
+ });
+ }
+
+ @Test
+ public void getAllAttributes_request_failure_404() {
+ final Response testReponse = new Response() {
+ @Override
+ public int getStatus() {
+ return 404;
+ }
+
+ @Override
+ public String getResponseText() {
+ return null;
+ }
+
+ @Override
+ public byte[] getResponseBytes() {
+ return new byte[0];
+ }
+
+ @Override
+ public Map> getHeaders() {
+ return null;
+ }
+ };
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ResponseListener responseListener = (ResponseListener) args[0];
+ responseListener.onFailure(testReponse, null, null);
+ return null;
+ }
+ }).when(stubRequest).send(any(ResponseListener.class), any(RequestBody.class), eq(expectedAccessToken));
+
+ userAttributeManagerSpy.getAllAttributes(expectedAccessToken, new UserAttributeResponseListener() {
+ @Override
+ public void onSuccess(JSONObject attributes) {
+ fail("should get to onFailure");
+
+ }
+
+ @Override
+ public void onFailure(UserAttributesException e) {
+ assertEquals(e.getError(), UserAttributesException.Error.NOT_FOUND);
+ }
+ });
+ }
+
+ @Test
+ public void getAllAttributes_happy_flow_no_token_supply() {
+
+ final Response testReponse = new Response() {
+ @Override
+ public int getStatus() {
+ return 200;
+ }
+
+ @Override
+ public String getResponseText() {
+ return "{\"age\": 30, \"email\":\"test@ibm.com\"}";
+ }
+
+ @Override
+ public byte[] getResponseBytes() {
+ return new byte[0];
+ }
+
+ @Override
+ public Map> getHeaders() {
+ return null;
+ }
+ };
+
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ResponseListener responseListener = (ResponseListener) args[0];
+ responseListener.onSuccess(testReponse);
+ return null;
+ }
+ }).when(stubRequest).send(any(ResponseListener.class), any(RequestBody.class), eq(expectedAccessToken));
+
+ userAttributeManagerSpy.getAllAttributes(new UserAttributeResponseListener() {
+ @Override
+ public void onSuccess(JSONObject attributes) {
+ try {
+ assertEquals(attributes.getInt("age"), 30);
+ assertEquals(attributes.getString("email"), "test@ibm.com");
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ @Override
+ public void onFailure(UserAttributesException e) {
+ fail("should get to onSuccess");
+ }
+ });
+
+ }
+
+ @Test
+ public void setAttribute_no_token_supply() {
+
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ResponseListener responseListener = (ResponseListener) args[0];
+ responseListener.onFailure(null, null, null);
+ return null;
+ }
+ }).when(stubRequest).send(any(ResponseListener.class), any(RequestBody.class), eq(expectedAccessToken));
+
+ final Response testReponse = new Response() {
+ @Override
+ public int getStatus() {
+ return 200;
+ }
+
+ @Override
+ public String getResponseText() {
+ return "{\"name\": \"testName\", \"value\":\"testValue\"}";
+ }
+
+ @Override
+ public byte[] getResponseBytes() {
+ return new byte[0];
+ }
+
+ @Override
+ public Map> getHeaders() {
+ return null;
+ }
+ };
+
+ Mockito.doReturn(specificStubRequest).when(userAttributeManagerSpy).createAppIDRequest(eq("https://appid-profiles.test/api/v1/attributes/testName"), eq(AppIDRequest.PUT));
+ Mockito.doReturn(stubRequestBody).when(userAttributeManagerSpy).createRequestBody(eq("testValue"));
+
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ResponseListener responseListener = (ResponseListener) args[0];
+ if ((RequestBody)args[1] != stubRequestBody){
+ responseListener.onFailure(null,null,null);
+ }
+ responseListener.onSuccess(testReponse);
+ return null;
+ }
+ }).when(specificStubRequest).send(any(ResponseListener.class), any(RequestBody.class), eq(expectedAccessToken));
+
+
+
+ userAttributeManagerSpy.setAttribute("testName","testValue",new UserAttributeResponseListener() {
+ @Override
+ public void onSuccess(JSONObject attributes) {
+ try {
+ assertEquals(attributes.getString("name"), "testName");
+ assertEquals(attributes.getString("value"), "testValue");
+ } catch (JSONException e) {
+ fail(e.getMessage());
+ e.printStackTrace();
+ }
+
+ }
+
+ @Override
+ public void onFailure(UserAttributesException e) {
+ fail("should get to onSuccess");
+ }
+ });
+
+ }
+
+ @Test
+ public void getAttribute_no_token_supply() {
+
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ResponseListener responseListener = (ResponseListener) args[0];
+ responseListener.onFailure(null, null, null);
+ return null;
+ }
+ }).when(stubRequest).send(any(ResponseListener.class), any(RequestBody.class), eq(expectedAccessToken));
+
+ final Response testReponse = new Response() {
+ @Override
+ public int getStatus() {
+ return 200;
+ }
+
+ @Override
+ public String getResponseText() {
+ return "{\"name\": \"testName\", \"value\":\"testValue\"}";
+ }
+
+ @Override
+ public byte[] getResponseBytes() {
+ return new byte[0];
+ }
+
+ @Override
+ public Map> getHeaders() {
+ return null;
+ }
+ };
+
+ Mockito.doReturn(specificStubRequest).when(userAttributeManagerSpy).createAppIDRequest(eq("https://appid-profiles.test/api/v1/attributes/testName"), eq(AppIDRequest.GET));
+ Mockito.doReturn(stubRequestBody).when(userAttributeManagerSpy).createRequestBody((String) eq(null));
+
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ResponseListener responseListener = (ResponseListener) args[0];
+ if ((RequestBody)args[1] != null) {
+ responseListener.onFailure(null,null,null);
+ }
+ responseListener.onSuccess(testReponse);
+ return null;
+ }
+ }).when(specificStubRequest).send(any(ResponseListener.class), any(RequestBody.class), eq(expectedAccessToken));
+
+
+ userAttributeManagerSpy.getAttribute("testName",new UserAttributeResponseListener() {
+ @Override
+ public void onSuccess(JSONObject attributes) {
+ try {
+ assertEquals(attributes.getString("name"), "testName");
+ assertEquals(attributes.getString("value"), "testValue");
+ } catch (JSONException e) {
+ fail(e.getMessage());
+ e.printStackTrace();
+ }
+
+ }
+
+ @Override
+ public void onFailure(UserAttributesException e) {
+ fail("should get to onSuccess");
+ }
+ });
+
+ }
+
+ @Test
+ public void deleteAttribute_no_token_supply() {
+
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ResponseListener responseListener = (ResponseListener) args[0];
+ responseListener.onFailure(null, null, null);
+ return null;
+ }
+ }).when(stubRequest).send(any(ResponseListener.class), any(RequestBody.class), eq(expectedAccessToken));
+
+ final Response testReponse = new Response() {
+ @Override
+ public int getStatus() {
+ return 200;
+ }
+
+ @Override
+ public String getResponseText() {
+ return "{\"name\": \"testName\", \"value\":\"testValue\"}";
+ }
+
+ @Override
+ public byte[] getResponseBytes() {
+ return new byte[0];
+ }
+
+ @Override
+ public Map> getHeaders() {
+ return null;
+ }
+ };
+
+ Mockito.doReturn(specificStubRequest).when(userAttributeManagerSpy).createAppIDRequest(eq("https://appid-profiles.test/api/v1/attributes/testName"), eq(AppIDRequest.DELETE));
+ Mockito.doReturn(stubRequestBody).when(userAttributeManagerSpy).createRequestBody((String) eq(null));
+
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ResponseListener responseListener = (ResponseListener) args[0];
+ if ((RequestBody)args[1] != null) {
+ responseListener.onFailure(null,null,null);
+ }
+ responseListener.onSuccess(testReponse);
+ return null;
+ }
+ }).when(specificStubRequest).send(any(ResponseListener.class), any(RequestBody.class), eq(expectedAccessToken));
+
+
+ userAttributeManagerSpy.deleteAttribute("testName",new UserAttributeResponseListener() {
+ @Override
+ public void onSuccess(JSONObject attributes) {
+ try {
+ assertEquals(attributes.getString("name"), "testName");
+ assertEquals(attributes.getString("value"), "testValue");
+ } catch (JSONException e) {
+ fail(e.getMessage());
+ e.printStackTrace();
+ }
+
+ }
+
+ @Override
+ public void onFailure(UserAttributesException e) {
+ fail("should get to onSuccess");
+ }
+ });
+
+ }
+}