Java tutorial
/************************************************************************* * Copyright 2009-2015 Eucalyptus Systems, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta * CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need * additional information or have any questions. ************************************************************************/ package com.eucalyptus.auth.euare; import java.security.cert.X509Certificate; import java.security.interfaces.RSAPublicKey; import java.util.List; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import javax.annotation.Nonnull; import com.eucalyptus.auth.AuthException; import com.eucalyptus.auth.euare.common.identity.Identity; import com.eucalyptus.auth.euare.persist.DatabasePrincipalProvider; import com.eucalyptus.auth.api.PrincipalProvider; import com.eucalyptus.auth.euare.identity.region.RegionConfigurationManager; import com.eucalyptus.auth.euare.identity.region.RegionConfigurations; import com.eucalyptus.auth.euare.identity.region.RegionInfo; import com.eucalyptus.auth.principal.AccountIdentifiers; import com.eucalyptus.auth.principal.InstanceProfile; import com.eucalyptus.auth.principal.Role; import com.eucalyptus.auth.principal.SecurityTokenContent; import com.eucalyptus.auth.principal.UserPrincipal; import com.eucalyptus.system.Threads; import com.eucalyptus.util.CollectionUtils; import com.eucalyptus.util.Either; import com.eucalyptus.util.Exceptions; import com.eucalyptus.util.FUtils; import com.eucalyptus.util.NonNullFunction; import com.eucalyptus.util.async.AsyncExceptions; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Predicates; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; /** * */ public class RegionDelegatingPrincipalProvider implements PrincipalProvider { private final PrincipalProvider localProvider = new DatabasePrincipalProvider(); private final RegionConfigurationManager regionConfigurationManager = new RegionConfigurationManager(); @Override public UserPrincipal lookupPrincipalByUserId(final String userId, final String nonce) throws AuthException { return regionDispatchByIdentifier(userId, new NonNullFunction<PrincipalProvider, UserPrincipal>() { @Nonnull @Override public UserPrincipal apply(final PrincipalProvider principalProvider) { try { return principalProvider.lookupPrincipalByUserId(userId, nonce); } catch (AuthException e) { throw Exceptions.toUndeclared(e); } } }); } @Override public UserPrincipal lookupPrincipalByRoleId(final String roleId, final String nonce) throws AuthException { return regionDispatchByIdentifier(roleId, new NonNullFunction<PrincipalProvider, UserPrincipal>() { @Nonnull @Override public UserPrincipal apply(final PrincipalProvider principalProvider) { try { return principalProvider.lookupPrincipalByRoleId(roleId, nonce); } catch (AuthException e) { throw Exceptions.toUndeclared(e); } } }); } @Override public UserPrincipal lookupPrincipalByAccessKeyId(final String keyId, final String nonce) throws AuthException { return regionDispatchByIdentifier(keyId, new NonNullFunction<PrincipalProvider, UserPrincipal>() { @Nonnull @Override public UserPrincipal apply(final PrincipalProvider principalProvider) { try { return principalProvider.lookupPrincipalByAccessKeyId(keyId, nonce); } catch (AuthException e) { throw Exceptions.toUndeclared(e); } } }); } @Override public UserPrincipal lookupPrincipalByCertificateId(final String certificateId) throws AuthException { return regionDispatchAndReduce( new NonNullFunction<PrincipalProvider, Either<AuthException, UserPrincipal>>() { @Nonnull @Override public Either<AuthException, UserPrincipal> apply(final PrincipalProvider principalProvider) { try { return Either.right(principalProvider.lookupPrincipalByCertificateId(certificateId)); } catch (AuthException e) { return Either.left(e); } } }); } @Override public UserPrincipal lookupPrincipalByCanonicalId(final String canonicalId) throws AuthException { return regionDispatchAndReduce( new NonNullFunction<PrincipalProvider, Either<AuthException, UserPrincipal>>() { @Nonnull @Override public Either<AuthException, UserPrincipal> apply(final PrincipalProvider principalProvider) { try { return Either.right(principalProvider.lookupPrincipalByCanonicalId(canonicalId)); } catch (AuthException e) { return Either.left(e); } } }); } @Override public UserPrincipal lookupPrincipalByAccountNumber(final String accountNumber) throws AuthException { return regionDispatchByAccountNumber(accountNumber, new NonNullFunction<PrincipalProvider, UserPrincipal>() { @Nonnull @Override public UserPrincipal apply(final PrincipalProvider principalProvider) { try { return principalProvider.lookupPrincipalByAccountNumber(accountNumber); } catch (AuthException e) { throw Exceptions.toUndeclared(e); } } }); } @Override public UserPrincipal lookupPrincipalByAccountNumberAndUsername(final String accountNumber, final String name) throws AuthException { return regionDispatchByAccountNumber(accountNumber, new NonNullFunction<PrincipalProvider, UserPrincipal>() { @Nonnull @Override public UserPrincipal apply(final PrincipalProvider principalProvider) { try { return principalProvider.lookupPrincipalByAccountNumberAndUsername(accountNumber, name); } catch (AuthException e) { throw Exceptions.toUndeclared(e); } } }); } @Override public UserPrincipal lookupCachedPrincipalByUserId(final UserPrincipal cached, final String userId, final String nonce) throws AuthException { return regionDispatchByIdentifier(userId, new NonNullFunction<PrincipalProvider, UserPrincipal>() { @Nonnull @Override public UserPrincipal apply(final PrincipalProvider principalProvider) { try { return principalProvider.lookupCachedPrincipalByUserId(cached, userId, nonce); } catch (AuthException e) { throw Exceptions.toUndeclared(e); } } }); } @Override public UserPrincipal lookupCachedPrincipalByRoleId(final UserPrincipal cached, final String roleId, final String nonce) throws AuthException { return regionDispatchByIdentifier(roleId, new NonNullFunction<PrincipalProvider, UserPrincipal>() { @Nonnull @Override public UserPrincipal apply(final PrincipalProvider principalProvider) { try { return principalProvider.lookupCachedPrincipalByRoleId(cached, roleId, nonce); } catch (AuthException e) { throw Exceptions.toUndeclared(e); } } }); } @Override public UserPrincipal lookupCachedPrincipalByAccessKeyId(final UserPrincipal cached, final String keyId, final String nonce) throws AuthException { return regionDispatchByIdentifier(keyId, new NonNullFunction<PrincipalProvider, UserPrincipal>() { @Nonnull @Override public UserPrincipal apply(final PrincipalProvider principalProvider) { try { return principalProvider.lookupCachedPrincipalByAccessKeyId(cached, keyId, nonce); } catch (AuthException e) { throw Exceptions.toUndeclared(e); } } }); } @Override public UserPrincipal lookupCachedPrincipalByCertificateId(final UserPrincipal cached, final String certificateId) throws AuthException { if (cached != null) { return regionDispatchByAccountNumber(cached.getAccountNumber(), new NonNullFunction<PrincipalProvider, UserPrincipal>() { @Nonnull @Override public UserPrincipal apply(final PrincipalProvider principalProvider) { try { return principalProvider.lookupCachedPrincipalByCertificateId(cached, certificateId); } catch (AuthException e) { throw Exceptions.toUndeclared(e); } } }); } else { return regionDispatchAndReduce( new NonNullFunction<PrincipalProvider, Either<AuthException, UserPrincipal>>() { @Nonnull @Override public Either<AuthException, UserPrincipal> apply( final PrincipalProvider principalProvider) { try { return Either.right(principalProvider.lookupCachedPrincipalByCertificateId(null, certificateId)); } catch (AuthException e) { return Either.left(e); } } }); } } @Override public UserPrincipal lookupCachedPrincipalByAccountNumber(final UserPrincipal cached, final String accountNumber) throws AuthException { return regionDispatchByAccountNumber(accountNumber, new NonNullFunction<PrincipalProvider, UserPrincipal>() { @Nonnull @Override public UserPrincipal apply(final PrincipalProvider principalProvider) { try { return principalProvider.lookupCachedPrincipalByAccountNumber(cached, accountNumber); } catch (AuthException e) { throw Exceptions.toUndeclared(e); } } }); } @Override public AccountIdentifiers lookupAccountIdentifiersByAlias(final String alias) throws AuthException { return regionDispatchAndReduce( new NonNullFunction<PrincipalProvider, Either<AuthException, AccountIdentifiers>>() { @Nonnull @Override public Either<AuthException, AccountIdentifiers> apply( final PrincipalProvider principalProvider) { try { return Either.right(principalProvider.lookupAccountIdentifiersByAlias(alias)); } catch (AuthException e) { return Either.left(e); } } }); } @Override public AccountIdentifiers lookupAccountIdentifiersByCanonicalId(final String canonicalId) throws AuthException { return regionDispatchAndReduce( new NonNullFunction<PrincipalProvider, Either<AuthException, AccountIdentifiers>>() { @Nonnull @Override public Either<AuthException, AccountIdentifiers> apply( final PrincipalProvider principalProvider) { try { return Either .right(principalProvider.lookupAccountIdentifiersByCanonicalId(canonicalId)); } catch (AuthException e) { return Either.left(e); } } }); } @Override public AccountIdentifiers lookupAccountIdentifiersByEmail(final String email) throws AuthException { return regionDispatchAndReduce( new NonNullFunction<PrincipalProvider, Either<AuthException, AccountIdentifiers>>() { @Nonnull @Override public Either<AuthException, AccountIdentifiers> apply( final PrincipalProvider principalProvider) { try { return Either.right(principalProvider.lookupAccountIdentifiersByEmail(email)); } catch (AuthException e) { return Either.left(e); } } }); } @Override public List<AccountIdentifiers> listAccountIdentifiersByAliasMatch(final String aliasExpression) throws AuthException { return regionDispatchAndReduce( new NonNullFunction<PrincipalProvider, Either<AuthException, List<AccountIdentifiers>>>() { @Nonnull @Override public Either<AuthException, List<AccountIdentifiers>> apply( final PrincipalProvider principalProvider) { try { return Either .right(principalProvider.listAccountIdentifiersByAliasMatch(aliasExpression)); } catch (AuthException e) { return Either.left(e); } } }, Lists.<AccountIdentifiers>newArrayList(), CollectionUtils.<AccountIdentifiers, List<AccountIdentifiers>>addAll()); } @Override public InstanceProfile lookupInstanceProfileByName(final String accountNumber, final String name) throws AuthException { return regionDispatchByAccountNumber(accountNumber, new NonNullFunction<PrincipalProvider, InstanceProfile>() { @Nonnull @Override public InstanceProfile apply(final PrincipalProvider principalProvider) { try { return principalProvider.lookupInstanceProfileByName(accountNumber, name); } catch (AuthException e) { throw Exceptions.toUndeclared(e); } } }); } @Override public Role lookupRoleByName(final String accountNumber, final String name) throws AuthException { return regionDispatchByAccountNumber(accountNumber, new NonNullFunction<PrincipalProvider, Role>() { @Nonnull @Override public Role apply(final PrincipalProvider principalProvider) { try { return principalProvider.lookupRoleByName(accountNumber, name); } catch (AuthException e) { throw Exceptions.toUndeclared(e); } } }); } @Override public SecurityTokenContent decodeSecurityToken(final String accessKeyIdentifier, final String securityToken) throws AuthException { return regionDispatchByIdentifier(accessKeyIdentifier, new NonNullFunction<PrincipalProvider, SecurityTokenContent>() { @Nonnull @Override public SecurityTokenContent apply(final PrincipalProvider principalProvider) { try { return principalProvider.decodeSecurityToken(accessKeyIdentifier, securityToken); } catch (AuthException e) { throw Exceptions.toUndeclared(e); } } }); } @Override public void reserveGlobalName(final String namespace, final String name, final Integer duration, final String clientToken) throws AuthException { final int numberOfRegions = Iterables.size(regionConfigurationManager.getRegionInfos()); final Integer successes = numberOfRegions <= 1 ? 1 : // skip if only a local region regionDispatchAndReduce(new NonNullFunction<PrincipalProvider, Either<AuthException, String>>() { @Nonnull @Override public Either<AuthException, String> apply(final PrincipalProvider identityProvider) { try { identityProvider.reserveGlobalName(namespace, name, duration, clientToken); return Either.right(""); } catch (AuthException e) { if (AsyncExceptions.isWebServiceErrorCode(e, AuthException.CONFLICT) || AuthException.CONFLICT.equals(e.getMessage())) { return Either.left(e); } else { throw Exceptions.toUndeclared(e); } } } }, 0, CollectionUtils.<String>count(Predicates.notNull())); if (successes < numberOfRegions) { throw new AuthException(AuthException.CONFLICT); } } @Override public X509Certificate getCertificateByAccountNumber(final String accountNumber) throws AuthException { return regionDispatchByAccountNumber(accountNumber, new NonNullFunction<PrincipalProvider, X509Certificate>() { @Nonnull @Override public X509Certificate apply(final PrincipalProvider principalProvider) { try { return principalProvider.getCertificateByAccountNumber(accountNumber); } catch (AuthException e) { throw Exceptions.toUndeclared(e); } } }); } @Override public X509Certificate signCertificate(final String accountNumber, final RSAPublicKey publicKey, final String principal, final int expiryInDays) throws AuthException { return regionDispatchByAccountNumber(accountNumber, new NonNullFunction<PrincipalProvider, X509Certificate>() { @Nonnull @Override public X509Certificate apply(final PrincipalProvider principalProvider) { try { return principalProvider.signCertificate(accountNumber, publicKey, principal, expiryInDays); } catch (AuthException e) { throw Exceptions.toUndeclared(e); } } }); } private <R> R regionDispatchByIdentifier(final String identifier, final NonNullFunction<PrincipalProvider, R> invoker) throws AuthException { return regionDispatch(regionConfigurationManager.getRegionByIdentifier(identifier), invoker); } private <R> R regionDispatchByAccountNumber(final String accountNumber, final NonNullFunction<PrincipalProvider, R> invoker) throws AuthException { return regionDispatch(regionConfigurationManager.getRegionByAccountNumber(accountNumber), invoker); } private <R> R regionDispatch(final Optional<RegionInfo> regionInfo, final NonNullFunction<PrincipalProvider, R> invoker) throws AuthException { try { if (regionInfo.isPresent() && !RegionConfigurations.getRegionName().asSet().contains(regionInfo.get().getName())) { final Optional<Set<String>> endpoints = regionInfo .transform(RegionInfo.serviceEndpoints("identity")); if (endpoints.isPresent() && !endpoints.get().isEmpty()) { final PrincipalProvider remoteProvider = new RemotePrincipalProvider(endpoints.get()); return invoker.apply(remoteProvider); } return invoker.apply(localProvider); } else { return invoker.apply(localProvider); } } catch (final RuntimeException e) { Exceptions.findAndRethrow(e, AuthException.class); throw e; } } private <R> R regionDispatchAndReduce( final NonNullFunction<PrincipalProvider, Either<AuthException, R>> invoker) throws AuthException { return regionDispatchAndReduce(invoker, null, CollectionUtils.<R>unique()); } private <R, I> I regionDispatchAndReduce( final NonNullFunction<PrincipalProvider, Either<AuthException, R>> invoker, final I initial, final Function<I, Function<R, I>> reducer) throws AuthException { try { final Iterable<RegionInfo> regionInfos = regionConfigurationManager.getRegionInfos(); final List<Either<AuthException, R>> regionResults = Lists.newArrayList(); regionResults.add(invoker.apply(localProvider)); if (!Iterables.isEmpty(regionInfos)) { final List<Future<Either<AuthException, R>>> regionResultFutures = Lists.newArrayList(); withRegions: for (final RegionInfo regionInfo : regionInfos) { if (!RegionConfigurations.getRegionName().asSet().contains(regionInfo.getName())) { for (final RegionInfo.RegionService service : regionInfo.getServices()) { if ("identity".equals(service.getType())) { final PrincipalProvider remoteProvider = new RemotePrincipalProvider( service.getEndpoints()); regionResultFutures.add( Threads.enqueue(Identity.class, RegionDelegatingPrincipalProvider.class, FUtils.cpartial(invoker, remoteProvider))); continue withRegions; } } } } for (final Future<Either<AuthException, R>> future : regionResultFutures) { try { regionResults.add(future.get()); } catch (final InterruptedException e) { throw new AuthException("Interrupted"); } catch (final ExecutionException e) { throw new RuntimeException(e); // Any AuthException caught and unwrapped below } } } final Iterable<R> successResults = Optional .presentInstances(Iterables.transform(regionResults, Either.<AuthException, R>rightOption())); if (Iterables.size(successResults) > 0) { return CollectionUtils.reduce(successResults, initial, reducer); } throw Iterables.get(Optional.presentInstances( Iterables.transform(regionResults, Either.<AuthException, R>leftOption())), 0); } catch (final RuntimeException e) { Exceptions.findAndRethrow(e, AuthException.class); throw e; } } }