com.auth0.lock.Lock.java Source code

Java tutorial

Introduction

Here is the source code for com.auth0.lock.Lock.java

Source

/*
 * Lock.java
 *
 * Copyright (c) 2014 Auth0 (http://auth0.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.auth0.lock;

import android.app.Activity;
import android.app.Application;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Base64;
import android.util.Log;

import com.auth0.api.APIClient;
import com.auth0.api.ParameterBuilder;
import com.auth0.api.authentication.AuthenticationAPIClient;
import com.auth0.api.internal.RequestFactory;
import com.auth0.core.Auth0;
import com.auth0.core.Strategies;
import com.auth0.identity.IdentityProvider;
import com.auth0.identity.WebIdentityProvider;
import com.auth0.identity.web.CallbackParser;
import com.auth0.lock.credentials.CredentialStore;
import com.auth0.lock.credentials.NullCredentialStore;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.squareup.otto.Bus;

import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Main class of Auth0 Lock SDK for Authentication through Auth0
 * This class handles all your Auth0 configuration and authentication using different Identity Providers.
 * Also this class provides a configured instance of {@link AuthenticationAPIClient} to call Auth0 Authentication API.
 * To start just instantiate it using {@link com.auth0.lock.Lock.Builder} like this inside your {@link Application} object:
 * <pre>
 *     <code>
 *      lock = new Lock.Builder()
 *              .loadFromApplication(this)
 *              .closable(true)
 *              .build();
 *     </code>
 * </pre>
 *
 * Then just invoke the login activity:
 * <pre>
 *     <code>
 *      Lock.getLock(activity).loginFromActivity(activity);
 *     </code>
 * </pre>
 */
public class Lock {

    /**
     * Action sent in {@link android.support.v4.content.LocalBroadcastManager} when a user authenticates.
     */
    public static final String AUTHENTICATION_ACTION = "Lock.Authentication";
    /**
     * Action sent when the user navigates back closing {@link com.auth0.lock.LockActivity}.
     */
    public static final String CANCEL_ACTION = "Lock.Cancel";
    /**
     * Action sent when the user change its password.
     */
    public static final String CHANGE_PASSWORD_ACTION = "Lock.ChangePassword";
    /**
     * Name of the parameter that will include user's profile.
     */
    public static final String AUTHENTICATION_ACTION_PROFILE_PARAMETER = "profile";
    /**
     * Name of the parameter that will include user's token information.
     */
    public static final String AUTHENTICATION_ACTION_TOKEN_PARAMETER = "token";

    private boolean useWebView;
    private boolean loginAfterSignUp;
    private boolean closable;
    private Map<String, Object> authenticationParameters;
    private boolean useEmail;
    private boolean fullScreen;

    private WebIdentityProvider defaultProvider;
    private Map<String, IdentityProvider> providers;

    private final Bus bus;
    private final APIClient apiClient;
    private final AuthenticationAPIClient authenticationAPIClient;

    private Configuration configuration;
    private List<String> connections;
    private String defaultDatabaseConnection;
    private boolean signUpEnabled;
    private boolean changePasswordEnabled;
    private CredentialStore credentialStore;

    Lock(Auth0 auth0) {
        this.useWebView = false;
        this.closable = false;
        this.loginAfterSignUp = true;
        this.useEmail = true;
        this.providers = new HashMap<>();
        this.bus = new Bus("Lock");
        this.defaultProvider = new WebIdentityProvider(new CallbackParser(), auth0.getClientId(),
                auth0.getAuthorizeUrl());
        this.apiClient = auth0.newAPIClient();
        this.authenticationAPIClient = auth0.newAuthenticationAPIClient();
        this.fullScreen = false;
        this.signUpEnabled = true;
        this.changePasswordEnabled = true;
        this.credentialStore = new NullCredentialStore();
    }

    /**
     * A instance of {@link com.auth0.api.APIClient} used by Lock
     *
     * @return a client
     * @deprecated Use {@link #getAuthenticationAPIClient()}
     */
    @Deprecated
    public APIClient getAPIClient() {
        return apiClient;
    }

    /**
     * An API client for Auth0 authentication API
     * @return
     */
    public AuthenticationAPIClient getAuthenticationAPIClient() {
        return authenticationAPIClient;
    }

    /**
     * A instance of {@link com.squareup.otto.Bus} where all internal events are sent.
     *
     * @return a bus used internally
     */
    public Bus getBus() {
        return bus;
    }

    /**
     * Force Lock to use an embedded {@link android.webkit.WebView}. Default is {@code false}
     * You'll also need to declare the following activity in your {@code AndroidManifest.xml}
     * <pre>{@code
     * <activity android:name="com.auth0.identity.web.WebViewActivity" android:theme="@style/Lock.Theme"/>
     * }</pre>
     *
     * @return if Lock uses a {@link android.webkit.WebView}. Default is false
     */
    public boolean shouldUseWebView() {
        return useWebView;
    }

    /**
     * Make Lock login a newly created user. Default is {@code true}
     *
     * @return If Lock performs signup + login
     */
    public boolean shouldLoginAfterSignUp() {
        return loginAfterSignUp;
    }

    /**
     * Allows Lock activities to be closed by pressing back button. Default is {@code false}
     *
     * @return if back button is enabled for Lock
     */
    public boolean isClosable() {
        return closable;
    }

    /**
     * Use Email to authenticate, otherwise use username. Default is {@code true}
     *
     * @return use email or username
     */
    public boolean shouldUseEmail() {
        return useEmail;
    }

    /**
     * Extra parameters sent to Auth0 API during authentication
     *
     * @return extra parameters for the API
     */
    public Map<String, Object> getAuthenticationParameters() {
        return authenticationParameters != null ? new HashMap<>(authenticationParameters)
                : new HashMap<String, Object>();
    }

    /**
     * Set a native handler for a specific Identity Provider (IdP), e.g.: Facebook
     *
     * @param serviceName name of the Auth0 strategy to handle. (For all valid values check {@link com.auth0.core.Strategies}
     * @param provider    IdP handler
     * @deprecated use {@link com.auth0.lock.Lock.Builder#withIdentityProvider(Strategies, IdentityProvider)} instead
     */
    public void setProvider(String serviceName, IdentityProvider provider) {
        providers.put(serviceName, provider);
    }

    /**
     * Finds a custom Identity Provider handler by service name.
     *
     * @param serviceName name of the service
     * @return a custom handler or null
     */
    public IdentityProvider providerForName(String serviceName) {
        IdentityProvider provider = providers.get(serviceName);
        return provider != null ? provider : defaultProvider;
    }

    /**
     * Default provider for every Auth0 Authentication strategy
     *
     * @return a default provider
     */
    public IdentityProvider getDefaultProvider() {
        return defaultProvider;
    }

    /**
     * Clears all session information stored in custom IdP handlers.
     */
    public void resetAllProviders() {
        for (IdentityProvider provider : this.providers.values()) {
            provider.stop();
        }
        this.defaultProvider.stop();
    }

    public Configuration getConfiguration() {
        return configuration;
    }

    public void setConfiguration(Configuration configuration) {
        this.configuration = configuration;
    }

    public List<String> getConnections() {
        return connections;
    }

    public String getDefaultDatabaseConnection() {
        return defaultDatabaseConnection;
    }

    /**
     * If Lock is displayed in fullscreen mode.
     * By default is false
     * @return if lock will be displayed in fullscreen
     */
    public boolean isFullScreen() {
        return fullScreen;
    }

    /**
     * If Lock has SignUp action enabled
     * By default is true
     * @return if the sign up action is enabled
     */
    public boolean isSignUpEnabled() {
        return signUpEnabled;
    }

    /**
     * If Lock has Change Password action enabled
     * By default is true
     * @return if the change password action is enabled
     */
    public boolean isChangePasswordEnabled() {
        return changePasswordEnabled;
    }

    /**
     * Lock's credential store for user's credentials e.g. Google's Smart Lock
     * By default no credentials are stored.
     *
     * @return an instance of CredentialStore
     */
    public CredentialStore getCredentialStore() {
        return credentialStore;
    }

    /**
     * Starts LockActivity from a given Activity
     *
     * @param activity from which LockActivity will be started
     */
    public void loginFromActivity(Activity activity) {
        Intent loginIntent = new Intent(activity, LockActivity.class);
        activity.startActivity(loginIntent);
    }

    /**
     * Returns the Lock object from the Application object.
     *
     * @param activity that needs Lock instance
     * @return a Lock instance
     */
    public static Lock getLock(Activity activity) {
        Application application = activity.getApplication();
        if (!(application instanceof LockProvider)) {
            throw new IllegalStateException("Android Application object must implement LockProvider interface");
        }
        LockProvider provider = (LockProvider) application;
        return provider.getLock();
    }

    /**
     * Builder for {@link com.auth0.lock.Lock}
     */
    public static class Builder {

        /**
         * Key for application meta-data where Lock checks for application's ClientId
         */
        public static final String CLIENT_ID_KEY = "com.auth0.lock.client-id";
        /**
         * Key for application meta-data where Lock checks for tenant name
         */
        public static final String TENANT_KEY = "com.auth0.lock.tenant";
        /**
         * Key for application meta-data where Lock checks for domain Url
         */
        public static final String DOMAIN_URL_KEY = "com.auth0.lock.domain-url";
        /**
         * Key for application meta-data where Lock checks for configuration Url
         */
        public static final String CONFIGURATION_URL_KEY = "com.auth0.lock.configuration-url";

        private String clientId;
        private String domain;
        private String configuration;
        private boolean useWebView;
        private boolean closable;
        private boolean loginAfterSignUp;
        private Map<String, Object> parameters;
        private boolean useEmail;
        private String defaultDBConnectionName;
        private List<String> connections;
        private boolean fullscreen;
        private boolean disableSignUp;
        private boolean disableChangePassword;
        private CredentialStore store;
        private Map<String, IdentityProvider> providers;
        private boolean sendSdkInfo;

        public Builder() {
            this.loginAfterSignUp = true;
            this.useEmail = true;
            this.fullscreen = false;
            this.parameters = ParameterBuilder.newBuilder().asDictionary();
            this.store = new NullCredentialStore();
            this.providers = new HashMap<>();
            this.sendSdkInfo = true;
        }

        /**
         * Set Auth0 application ClientID
         *
         * @param clientId clientId
         * @return the Builder instance being used
         */
        public Builder clientId(String clientId) {
            this.clientId = clientId;
            return this;
        }

        /**
         * Set Auth0 account tenant name
         *
         * @param tenant tenant name
         * @return the Builder instance being used
         * @deprecated since 1.7.0
         */
        @Deprecated
        public Builder tenant(String tenant) {
            if (tenant != null) {
                domainUrl(tenant + ".auth0.com");
            }
            return this;
        }

        /**
         * Set the default domain Url for Auth0 API
         *
         * @param domain url of the domain where Auth0 API is deployed
         * @return the Builder instance being used
         */
        public Builder domainUrl(String domain) {
            if (domain != null && domain.startsWith("http://")) {
                Log.w(Builder.class.getName(), "You should use (https) instead of (http) for url " + domain);
            }
            this.domain = domain;
            return this;
        }

        /**
         * Set the Url where the app information can be retrieved
         *
         * @param configuration Url that returns the app info.
         * @return the Builder instance being used
         */
        public Builder configurationUrl(String configuration) {
            if (configuration != null && configuration.startsWith("http://")) {
                Log.w(Builder.class.getName(), "You should use (https) instead of (http) for url " + configuration);
            }
            this.configuration = configuration;
            return this;
        }

        /**
         * Use an embedded WebView instead of an external browser
         *
         * @param useWebView if Lock will use an embedded WebView or an external browser
         * @return the Builder instance being used
         */
        public Builder useWebView(boolean useWebView) {
            this.useWebView = useWebView;
            return this;
        }

        /**
         * If the login screen can be closed/dismissed
         *
         * @param closable if Lock will allow the login screen to be closed
         * @return the Builder instance being used
         */
        public Builder closable(boolean closable) {
            this.closable = closable;
            return this;
        }

        /**
         * If after a successful sign up, the user will be logged in too.
         *
         * @param loginAfterSignUp if Lock should login a user after sign up
         * @return the Builder instance being used
         */
        public Builder loginAfterSignUp(boolean loginAfterSignUp) {
            this.loginAfterSignUp = loginAfterSignUp;
            return this;
        }

        /**
         * Extra authentication parameters to send to Auth0 Auth API.
         *
         * @param parameters a map with extra parameters for the API.
         * @return the Builder instance being used
         */
        public Builder authenticationParameters(Map<String, Object> parameters) {
            this.parameters = parameters != null ? parameters : ParameterBuilder.newBuilder().asDictionary();
            return this;
        }

        /**
         * Make Lock pick these connections for authentication from all the enabled connections in your app.
         * If the connection is not active in your application it will be ignored.
         *
         * @param connectionNames List of names of connections to use.
         * @return the Builder instance being used
         */
        @SuppressWarnings("unused")
        public Builder useConnections(String... connectionNames) {
            this.connections = Arrays.asList(connectionNames);
            return this;
        }

        /**
         * Specify the DB connection used by Lock.
         *
         * @param name DB connection name
         * @return the Builder instance being used.
         */
        @SuppressWarnings("unused")
        public Builder defaultDatabaseConnection(String name) {
            this.defaultDBConnectionName = name;
            return this;
        }

        /**
         * Shows Lock in Fullscreen mode.
         *
         * @param fullscreen if lock is displayed in fullscreen
         * @return the Builder instance being used
         */
        public Builder fullscreen(boolean fullscreen) {
            this.fullscreen = fullscreen;
            return this;
        }

        /**
         * Disables Sign Up action
         * @param disableSignUp or not
         * @return the Builder instance being used
         */
        public Builder disableSignUp(boolean disableSignUp) {
            this.disableSignUp = disableSignUp;
            return this;
        }

        /**
         * Disables Change Password action
         * @param disableChangePassword or not
         * @return the Builder instance being used
         */
        public Builder disableChangePassword(boolean disableChangePassword) {
            this.disableChangePassword = disableChangePassword;
            return this;
        }

        /**
         * If it should ask for email or username. By default is <code>true</code>
         *
         * @param useEmail if Lock ask for email or username.
         * @return the Builder instance being used
         */
        public Builder useEmail(boolean useEmail) {
            this.useEmail = useEmail;
            return this;
        }

        /**
         * The credential store that Lock will use to store user's credentials on Sign Up.
         *
         * @param store a credential store
         * @return the Builder instance being used
         */
        public Builder useCredentialStore(CredentialStore store) {
            if (store != null) {
                this.store = store;
            } else {
                this.store = new NullCredentialStore();
            }
            return this;
        }

        /**
         * Sets a native handler for a specific Identity Provider (IdP), e.g.: Facebook
         *
         * @param strategy Auth0 strategy to handle. (For all valid values check {@link com.auth0.core.Strategies}
         * @param identityProvider IdP handler
         * @return the Builder instance being used
         */
        public Builder withIdentityProvider(Strategies strategy, IdentityProvider identityProvider) {
            providers.put(strategy.getName(), identityProvider);
            return this;
        }

        /**
         * Avoid sending SDK info with API requests
         * @return the Builder instance being used
         */
        @SuppressWarnings("unused")
        public Builder doNotSendSDKInfo() {
            sendSdkInfo = false;
            return this;
        }

        /**
         * Create a {@link com.auth0.lock.Lock} instance with the values stored.
         * @return a new Lock instance`
         */
        public Lock build() {
            Lock lock = buildLock();
            lock.useWebView = useWebView;
            lock.defaultProvider.setUseWebView(useWebView);
            lock.loginAfterSignUp = loginAfterSignUp;
            lock.closable = closable;
            lock.authenticationParameters = parameters;
            lock.defaultProvider.setParameters(parameters);
            lock.useEmail = useEmail;
            lock.connections = connections;
            lock.defaultDatabaseConnection = defaultDBConnectionName;
            lock.fullScreen = fullscreen;
            lock.signUpEnabled = !disableSignUp;
            lock.changePasswordEnabled = !disableChangePassword;
            lock.credentialStore = store;
            lock.providers = new HashMap<>(providers);
            if (sendSdkInfo) {
                final String clientInfo = buildClientInfo();
                lock.apiClient.setClientInfo(clientInfo);
                lock.defaultProvider.setClientInfo(clientInfo);
                RequestFactory.setClientInfo(clientInfo);
            }
            return lock;
        }

        /**
         * Load ClientID, Tenant name, Domain and configuration URLs from the Android app's metadata (if available).
         * These are the values that can be defined and it's keys:
         * <ul>
         * <li>{@link #CLIENT_ID_KEY}: Application's clientId in Auth0.</li>
         * <li>{@link #TENANT_KEY}: Application's owner tenant name. (Optional if you supply Domain and Configuration URLs)</li>
         * <li>{@link #DOMAIN_URL_KEY}: URL where the Auth0 API is available. (Optional if you supply ClientID/Tenant and you use Auth0 in the cloud)</li>
         * <li>{@link #CONFIGURATION_URL_KEY}: URL where Auth0 apps information is available. (Optional if you supply ClientID/Tenant and you use Auth0 in the cloud)</li>
         * </ul>
         *
         * @param application an instance of {@link android.app.Application}
         * @return the Builder instance being used
         */
        @SuppressWarnings("deprecation")
        public Builder loadFromApplication(Application application) {
            try {
                ApplicationInfo ai = application.getPackageManager()
                        .getApplicationInfo(application.getPackageName(), PackageManager.GET_META_DATA);
                Bundle bundle = ai.metaData;
                this.clientId(bundle.getString(CLIENT_ID_KEY)).tenant(bundle.getString(TENANT_KEY))
                        .domainUrl(bundle.getString(DOMAIN_URL_KEY))
                        .configurationUrl(bundle.getString(CONFIGURATION_URL_KEY));
            } catch (PackageManager.NameNotFoundException e) {
                throw new IllegalArgumentException("Failed to read info from AndroidManifest.xml", e);
            }
            return this;
        }

        protected Auth0 buildAuth0() {
            if (this.clientId == null || this.domain == null) {
                throw new IllegalArgumentException(
                        "Missing Auth0 credentials. Please make sure you supplied at least ClientID and Domain.");
            }
            return new Auth0(this.clientId, this.domain, this.configuration);
        }

        protected Lock buildLock() {
            return new Lock(buildAuth0());
        }

        protected String buildClientInfo() {
            Map<String, String> info = new HashMap<>();
            info.put("name", "Lock.Android");
            info.put("version", BuildConfig.VERSION_NAME);
            String clientInfo = null;
            try {
                String json = new ObjectMapper().writeValueAsString(info);
                clientInfo = Base64.encodeToString(json.getBytes(Charset.defaultCharset()),
                        Base64.URL_SAFE | Base64.NO_WRAP);
            } catch (JsonProcessingException e) {
                Log.w(Lock.class.getName(), "Failed to build client info", e);
            }
            return clientInfo;
        }
    }
}