package io.cattle.platform.iaas.api.auth.integration.azure; import io.cattle.platform.api.auth.Identity; import io.cattle.platform.core.constants.IdentityConstants; import io.cattle.platform.core.constants.ProjectConstants; import io.cattle.platform.core.model.Account; import io.cattle.platform.core.model.AuthToken; import io.cattle.platform.iaas.api.auth.SecurityConstants; import io.cattle.platform.iaas.api.auth.dao.AuthTokenDao; import io.cattle.platform.iaas.api.auth.integration.interfaces.IdentityProvider; import io.cattle.platform.object.util.DataAccessor; import io.github.ibuildthecloud.gdapi.context.ApiContext; import io.github.ibuildthecloud.gdapi.exception.ClientVisibleException; import io.github.ibuildthecloud.gdapi.request.ApiRequest; import io.github.ibuildthecloud.gdapi.util.ResponseCodes; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.inject.Inject; import org.apache.commons.lang3.StringUtils; public class AzureIdentityProvider extends AzureConfigurable implements IdentityProvider { @Inject AzureRESTClient azureClient; @Inject private AzureTokenUtil azureTokenUtils; @Inject private AuthTokenDao authTokenDao; @Inject AzureTokenCreator azureTokenCreator; @Override public List<Identity> searchIdentities(String name, boolean exactMatch) { if (!isConfigured()) { notConfigured(); } List<Identity> identities = new ArrayList<>(); for (String scope : scopes()) { identities.addAll(searchIdentities(name, scope, exactMatch)); } return identities; } @Override public List<Identity> searchIdentities(String name, String scope, boolean exactMatch) { //TODO:Implement exact match. if (!isConfigured()){ notConfigured(); } switch (scope){ case AzureConstants.USER_SCOPE: return searchUsers(name, exactMatch); case AzureConstants.GROUP_SCOPE: return searchGroups(name, exactMatch); default: return new ArrayList<>(); } } @Override public Set<Identity> getIdentities(Account account) { if (!isConfigured() || !AzureConstants.USER_SCOPE.equalsIgnoreCase(account.getExternalIdType())) { return new HashSet<>(); } String accessToken = (String) DataAccessor.fields(account).withKey(AzureConstants.AZURE_ACCESS_TOKEN).get(); String refreshToken = (String) DataAccessor.fields(account).withKey(AzureConstants.AZURE_REFRESH_TOKEN).get(); if (azureTokenUtils.findAndSetJWT()){ ApiRequest request = ApiContext.getContext().getApiRequest(); request.setAttribute(AzureConstants.AZURE_ACCESS_TOKEN, accessToken); request.setAttribute(AzureConstants.AZURE_REFRESH_TOKEN, refreshToken); return azureTokenUtils.getIdentities(); } String jwt = null; if (!StringUtils.isBlank(accessToken) && SecurityConstants.SECURITY.get()) { AuthToken authToken = authTokenDao.getTokenByAccountId(account.getId()); if (authToken == null) { try { jwt = ProjectConstants.AUTH_TYPE + azureTokenCreator.getAzureToken(accessToken).getJwt(); authToken = authTokenDao.createToken(jwt, AzureConstants.CONFIG, account.getId()); jwt = authToken.getKey(); } catch (ClientVisibleException e) { if (e.getCode().equalsIgnoreCase(AzureConstants.AZURE_ERROR) && !e.getDetail().contains("401")) { throw new ClientVisibleException(ResponseCodes.INTERNAL_SERVER_ERROR, AzureConstants.JWT_CREATION_FAILED, "", null); } } } else { jwt = authToken.getKey(); } } if (StringUtils.isBlank(jwt)){ return Collections.emptySet(); } ApiRequest request = ApiContext.getContext().getApiRequest(); request.setAttribute(AzureConstants.AZURE_JWT, jwt); request.setAttribute(AzureConstants.AZURE_ACCESS_TOKEN, accessToken); request.setAttribute(AzureConstants.AZURE_REFRESH_TOKEN, refreshToken); return azureTokenUtils.getIdentities(); } private List<Identity> searchGroups(String groupName, boolean exactMatch) { List<Identity> identities = new ArrayList<>(); AzureAccountInfo group; try { group = azureClient.getAzureGroupByName(groupName); if (group == null){ return identities; } } catch (ClientVisibleException e) { return identities; } Identity identity = group.toIdentity(AzureConstants.GROUP_SCOPE); identities.add(identity); return identities; } private List<Identity> searchUsers(String userName, boolean exactMatch) { List<Identity> identities = new ArrayList<>(); AzureAccountInfo user; try { user = azureClient.getAzureUserByName(userName); } catch (ClientVisibleException e) { return identities; } if (user == null) { return identities; } Identity identity = user.toIdentity(AzureConstants.USER_SCOPE); identities.add(identity); return identities; } @Override public Identity getIdentity(String id, String scope) { if (!isConfigured()){ notConfigured(); } switch (scope) { case AzureConstants.USER_SCOPE: AzureAccountInfo user = azureClient.getUserById(id); return user.toIdentity(AzureConstants.USER_SCOPE); case AzureConstants.GROUP_SCOPE: AzureAccountInfo org = azureClient.getGroupById(id); return org.toIdentity(AzureConstants.GROUP_SCOPE); default: throw new ClientVisibleException(ResponseCodes.BAD_REQUEST, IdentityConstants.INVALID_TYPE, "Invalid scope for AzureSearchProvider", null); } } private void notConfigured() { throw new ClientVisibleException(ResponseCodes.SERVICE_UNAVAILABLE, "NotConfigured", "Azure is not configured", null); } @Override public Set<String> scopes() { return AzureConstants.SCOPES; } @Override public String getName() { return AzureConstants.SEARCH_PROVIDER; } @Override public Identity transform(Identity identity) { if (scopes().contains(identity.getExternalIdType())) { return getIdentity(identity.getExternalId(), identity.getExternalIdType()); } throw new ClientVisibleException(ResponseCodes.BAD_REQUEST, IdentityConstants.INVALID_TYPE, "Azure does not provide: " + identity.getExternalIdType(), null ); } @Override public Identity untransform(Identity identity) { if (scopes().contains(identity.getExternalIdType())) { return identity; } throw new ClientVisibleException(ResponseCodes.BAD_REQUEST, IdentityConstants.INVALID_TYPE, "Azure does not provide: " + identity.getExternalIdType(), null ); } }