com.microsoft.alm.plugin.authentication.AuthHelper.java Source code

Java tutorial

Introduction

Here is the source code for com.microsoft.alm.plugin.authentication.AuthHelper.java

Source

// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root.

package com.microsoft.alm.plugin.authentication;

import com.google.common.util.concurrent.SettableFuture;
import com.microsoft.alm.client.model.VssServiceResponseException;
import com.microsoft.alm.common.utils.SystemHelper;
import com.microsoft.alm.plugin.context.ServerContext;
import com.microsoft.visualstudio.services.delegatedauthorization.SessionToken;
import com.microsoftopentechnologies.auth.AuthenticationResult;
import org.apache.commons.lang.StringUtils;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.NTCredentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.NotAuthorizedException;
import java.util.Date;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * Static helpers for Authentication
 */
public class AuthHelper {
    private final static Logger logger = LoggerFactory.getLogger(AuthHelper.class);

    /**
     * Personal Access Token description string formatter
     */
    private static final String TOKEN_DESCRIPTION_FORMATTER = "VSTS IntelliJ Plugin: %s from: %s on: %s";

    public static AuthenticationInfo createAuthenticationInfo(final String serverUri,
            final Credentials credentials) {
        return new AuthenticationInfo(credentials.getUserPrincipal().getName(), credentials.getPassword(),
                serverUri, credentials.getUserPrincipal().getName());
    }

    public static AuthenticationInfo createAuthenticationInfo(final String serverUri,
            final AuthenticationResult authenticationResult) {
        return new AuthenticationInfo(getUserId(authenticationResult), getPassword(authenticationResult), serverUri,
                getEmail(authenticationResult));
    }

    public static AuthenticationInfo createAuthenticationInfo(final String serverUri,
            final AuthenticationResult authenticationResult, final SessionToken sessionToken) {
        return new AuthenticationInfo(getUserId(authenticationResult), sessionToken.getToken(), serverUri,
                getEmail(authenticationResult));
    }

    /**
     * This method wraps the normal Async call to authenticate and waits on the result.
     */
    public static AuthenticationInfo getAuthenticationInfoSynchronously(final AuthenticationProvider provider,
            final String gitRemoteUrl) {
        final SettableFuture<AuthenticationInfo> future = SettableFuture.create();

        provider.authenticateAsync(gitRemoteUrl, new AuthenticationListener() {
            @Override
            public void authenticating() {
                // do nothing
            }

            @Override
            public void authenticated(final AuthenticationInfo authenticationInfo, final Throwable throwable) {
                if (throwable != null) {
                    future.setException(throwable);
                } else {
                    future.set(authenticationInfo);
                }
            }
        });

        // Wait for the authentication info object to be ready
        // Don't wait any longer than 15 minutes for the user to authenticate
        Throwable t = null;
        try {
            return future.get(15, TimeUnit.MINUTES);
        } catch (InterruptedException ie) {
            t = ie;
        } catch (ExecutionException ee) {
            t = ee;
        } catch (TimeoutException te) {
            t = te;
        } finally {
            if (t != null) {
                logger.error("getAuthenticationInfoSynchronously: failed to get authentication info from user");
                logger.warn("getAuthenticationInfoSynchronously", t);
            }
        }
        return null;
    }

    /**
     * Returns the NTCredentials or UsernamePasswordCredentials object
     *
     * @param type
     * @param authenticationInfo
     * @return
     */
    public static Credentials getCredentials(final ServerContext.Type type,
            final AuthenticationInfo authenticationInfo) {
        if (type == ServerContext.Type.TFS) {
            return getNTCredentials(authenticationInfo.getUserName(), authenticationInfo.getPassword());
        } else {
            return new UsernamePasswordCredentials(authenticationInfo.getUserName(),
                    authenticationInfo.getPassword());
        }
    }

    /**
     * Returns an NTCredentials object for given username and password
     *
     * @param userName
     * @param password
     * @return
     */
    public static NTCredentials getNTCredentials(final String userName, final String password) {
        assert userName != null;
        assert password != null;

        String user = userName;
        String domain = "";
        final String workstation = SystemHelper.getComputerName();

        // If the username has a backslash, then the domain is the first part and the username is the second part
        if (userName.contains("\\")) {
            String[] parts = userName.split("[\\\\]");
            if (parts.length == 2) {
                domain = parts[0];
                user = parts[1];
            }
        } else if (userName.contains("/")) {
            // If the username has a slash, then the domain is the first part and the username is the second part
            String[] parts = userName.split("[/]");
            if (parts.length == 2) {
                domain = parts[0];
                user = parts[1];
            }
        } else if (userName.contains("@")) {
            // If the username has an asterisk, then the domain is the second part and the username is the first part
            String[] parts = userName.split("[@]");
            if (parts.length == 2) {
                user = parts[0];
                domain = parts[1];
            }
        }

        return new org.apache.http.auth.NTCredentials(user, password, workstation, domain);
    }

    private static String getUserId(final AuthenticationResult authenticationResult) {
        return authenticationResult.getUserInfo().getUniqueName();
    }

    private static String getPassword(final AuthenticationResult authenticationResult) {
        return authenticationResult.getAccessToken();
    }

    public static String getEmail(final AuthenticationResult authenticationResult) {
        final String email;
        final String identityProvider = authenticationResult.getUserInfo().getIdentityProvider();
        if (identityProvider == null || identityProvider.isEmpty()) {
            email = authenticationResult.getUserInfo().getUniqueName();
        } else {
            email = authenticationResult.getUserInfo().getUniqueName().substring(identityProvider.length() + 1);
        }
        return email;
    }

    public static String getTokenDescription(final String emailAddress) {
        final String tokenDescription = String.format(TOKEN_DESCRIPTION_FORMATTER, emailAddress,
                SystemHelper.getComputerName(), new Date().toString());

        return tokenDescription;
    }

    public static boolean isNotAuthorizedError(final Throwable throwable) {
        //We get VssServiceResponseException when token is valid but does not have the required scopes
        //statusCode on VssServiceResponseException is set to 401 but that is not accessible, so we have to check the message
        //If the message gets localized, we won't detect the auth error
        if (throwable != null
                && (throwable instanceof NotAuthorizedException || (throwable instanceof VssServiceResponseException
                        && StringUtils.containsIgnoreCase(throwable.getMessage(), "unauthorized")))) {
            return true;
        }

        if (throwable != null && throwable.getCause() != null
                && (throwable.getCause() instanceof NotAuthorizedException
                        || (throwable.getCause() instanceof VssServiceResponseException
                                && (StringUtils.containsIgnoreCase(throwable.getMessage(), "unauthorized"))))) {
            return true;
        }

        return false;
    }
}