package lenala.azure.gradle.functions.auth; import com.microsoft.azure.AzureEnvironment; import com.microsoft.azure.credentials.ApplicationTokenCredentials; import com.microsoft.azure.credentials.AzureCliCredentials; import com.microsoft.azure.management.Azure; import com.microsoft.azure.management.Azure.Authenticated; import com.microsoft.rest.LogLevel; import org.apache.commons.lang3.StringUtils; import org.gradle.api.logging.Logger; import org.gradle.api.logging.Logging; import java.io.File; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Locale; /** * Helper class to authenticate with Azure */ public class AzureAuthHelper { public static final String CLIENT_ID = "client"; private static final String TENANT_ID = "tenant"; private static final String KEY = "key"; private static final String CERTIFICATE = "certificate"; private static final String CERTIFICATE_PASSWORD = "certificatePassword"; private static final String ENVIRONMENT = "environment"; private static final String AUTH_WITH_CLIENT_ID = "Authenticate with clientId: "; private static final String AUTH_WITH_FILE = "Authenticate with file: "; private static final String AUTH_WITH_AZURE_CLI = "Authenticate with Azure CLI 2.0"; private static final String USE_KEY_TO_AUTH = "Use key to get Azure authentication token: "; private static final String USE_CERTIFICATE_TO_AUTH = "Use certificate to get Azure authentication token."; private static final String CLIENT_ID_NOT_CONFIG = "Client Id of your service principal is not configured."; private static final String TENANT_ID_NOT_CONFIG = "Tenant Id of your service principal is not configured."; private static final String KEY_NOT_CONFIG = "Key of your service principal is not configured."; private static final String CERTIFICATE_FILE_NOT_CONFIG = "Certificate of your service principal is not configured."; private static final String CERTIFICATE_FILE_READ_FAIL = "Failed to read certificate file: "; private static final String AUTH_FILE_NOT_CONFIG = "Authentication file is not configured."; private static final String AUTH_FILE_NOT_EXIST = "Authentication file does not exist: "; private static final String AUTH_FILE_READ_FAIL = "Failed to read authentication file: "; private static final String AZURE_CLI_AUTH_FAIL = "Failed to authenticate with Azure CLI 2.0"; private AuthConfiguration config; private Logger logger = Logging.getLogger(AzureAuthHelper.class); /** * Constructor * * @param config */ public AzureAuthHelper(final AuthConfiguration config) { if (config == null) { throw new NullPointerException(); } this.config = config; } public Azure getAzureClient() { final Authenticated auth = getAuthObj(); if (auth == null) { return null; } try { final String subscriptionId = config.getSubscriptionId(); return StringUtils.isEmpty(subscriptionId) ? auth.withDefaultSubscription() : auth.withSubscription(subscriptionId); } catch (Exception e) { logger.debug("", e); } return null; } private LogLevel getLogLevel() { return logger.isDebugEnabled() ? LogLevel.BODY_AND_HEADERS : LogLevel.NONE; } private Azure.Configurable azureConfigure() { return Azure.configure() .withLogLevel(getLogLevel()) .withUserAgent(config.getUserAgent()); } private AzureEnvironment getAzureEnvironment(String environment) { if (StringUtils.isEmpty(environment)) { return AzureEnvironment.AZURE; } switch (environment.toUpperCase(Locale.ENGLISH)) { case "AZURE_CHINA": return AzureEnvironment.AZURE_CHINA; case "AZURE_GERMANY": return AzureEnvironment.AZURE_GERMANY; case "AZURE_US_GOVERNMENT": return AzureEnvironment.AZURE_US_GOVERNMENT; default: return AzureEnvironment.AZURE; } } private Authenticated getAuthObj() { Authenticated auth; // check if project has Azure authentication settings in build.gradle or gradle.properties boolean hasAuthSetting = config.hasAuthenticationSettings(); if (hasAuthSetting) { auth = getAuthObjFromConfiguration(config); if (auth == null) { auth = getAuthObjFromFile(new File(config.getAuthFile())); } } else { auth = getAuthObjFromAzureCli(); } return auth; } /** * Get Authenticated object by reading app token credentials from gradle.properties * * @return Authenticated object if configurations are correct; otherwise return null. */ private Authenticated getAuthObjFromConfiguration(final AuthConfiguration config) { final ApplicationTokenCredentials credential = getAppTokenCredentials(); if (credential == null) { return null; } final Authenticated auth = azureConfigure().authenticate(credential); if (auth != null) { logger.quiet(AUTH_WITH_CLIENT_ID + config.getAuthenticationSetting(CLIENT_ID)); } return auth; } /** * Get Authenticated object using file. * * @param authFile Authentication file object. * @return Authenticated object of file is valid; otherwise return null. */ private Authenticated getAuthObjFromFile(final File authFile) { if (authFile == null) { logger.debug(AUTH_FILE_NOT_CONFIG); return null; } if (!authFile.exists()) { logger.error(AUTH_FILE_NOT_EXIST + authFile.getAbsolutePath()); return null; } try { final Authenticated auth = azureConfigure().authenticate(authFile); if (auth != null) { logger.quiet(AUTH_WITH_FILE + authFile.getAbsolutePath()); } return auth; } catch (Exception e) { logger.error(AUTH_FILE_READ_FAIL + authFile.getAbsolutePath(), e); } return null; } /** * Get Authenticated object using authentication file from Azure CLI 2.0 * * @return Authenticated object if Azure CLI 2.0 is logged in correctly; otherwise return null. */ private Authenticated getAuthObjFromAzureCli() { try { final Authenticated auth = azureConfigure().authenticate(AzureCliCredentials.create()); if (auth != null) { logger.quiet(AUTH_WITH_AZURE_CLI); } return auth; } catch (Exception e) { logger.debug(AZURE_CLI_AUTH_FAIL, e); } return null; } /** * Get ApplicationTokenCredentials from authentication settings in gradle.properties. * * @return ApplicationTokenCredentials object if configuration is correct; otherwise return null. */ private ApplicationTokenCredentials getAppTokenCredentials() { final String clientId = config.getAuthenticationSetting(CLIENT_ID); if (StringUtils.isEmpty(clientId)) { logger.quiet(CLIENT_ID_NOT_CONFIG); return null; } final String tenantId = config.getAuthenticationSetting(TENANT_ID); if (StringUtils.isEmpty(tenantId)) { logger.quiet(TENANT_ID_NOT_CONFIG); return null; } final String environment = config.getAuthenticationSetting(ENVIRONMENT); final AzureEnvironment azureEnvironment = getAzureEnvironment(environment); logger.quiet("Azure Management Endpoint: " + azureEnvironment.managementEndpoint()); final String key = config.getAuthenticationSetting(KEY); if (!StringUtils.isEmpty(key)) { logger.quiet(USE_KEY_TO_AUTH); return new ApplicationTokenCredentials(clientId, tenantId, key, azureEnvironment); } else { logger.quiet(KEY_NOT_CONFIG); } final String certificate = config.getAuthenticationSetting(CERTIFICATE); if (StringUtils.isEmpty(certificate)) { logger.quiet(CERTIFICATE_FILE_NOT_CONFIG); return null; } final String certificatePassword = config.getAuthenticationSetting(CERTIFICATE_PASSWORD); try { byte[] cert; cert = Files.readAllBytes(Paths.get(certificate, new String[0])); logger.quiet(USE_CERTIFICATE_TO_AUTH + certificate); return new ApplicationTokenCredentials(clientId, tenantId, cert, certificatePassword, azureEnvironment); } catch (Exception e) { logger.quiet(CERTIFICATE_FILE_READ_FAIL + certificate); } return null; } }