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.persist; import java.security.cert.X509Certificate; import java.security.interfaces.RSAPublicKey; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.NoSuchElementException; import java.util.concurrent.TimeUnit; import javax.annotation.Nullable; import org.hibernate.FlushMode; import org.hibernate.criterion.Restrictions; import org.hibernate.exception.ConstraintViolationException; import com.eucalyptus.auth.AccessKeys; import com.eucalyptus.auth.euare.Accounts; import com.eucalyptus.auth.AuthException; import com.eucalyptus.auth.InvalidAccessKeyAuthException; import com.eucalyptus.auth.api.PrincipalProvider; import com.eucalyptus.auth.euare.EuareServerCertificateUtil; import com.eucalyptus.auth.euare.persist.entities.AccessKeyEntity; import com.eucalyptus.auth.euare.persist.entities.AccountEntity; import com.eucalyptus.auth.euare.persist.entities.CertificateEntity; import com.eucalyptus.auth.euare.persist.entities.InstanceProfileEntity; import com.eucalyptus.auth.euare.persist.entities.ReservedNameEntity; import com.eucalyptus.auth.euare.persist.entities.RoleEntity; import com.eucalyptus.auth.euare.persist.entities.UserEntity; import com.eucalyptus.auth.euare.principal.EuareRole; import com.eucalyptus.auth.euare.principal.EuareUser; import com.eucalyptus.auth.euare.principal.GlobalNamespace; import com.eucalyptus.auth.principal.AccessKey; import com.eucalyptus.auth.principal.AccountIdentifiers; import com.eucalyptus.auth.principal.Certificate; import com.eucalyptus.auth.euare.principal.EuareInstanceProfile; import com.eucalyptus.auth.principal.InstanceProfile; import com.eucalyptus.auth.principal.PolicyVersion; import com.eucalyptus.auth.principal.Role; import com.eucalyptus.auth.principal.SecurityTokenContent; import com.eucalyptus.auth.principal.UserPrincipal; import com.eucalyptus.auth.euare.UserPrincipalImpl; import com.eucalyptus.auth.tokens.SecurityTokenManager; import com.eucalyptus.component.annotation.ComponentNamed; import com.eucalyptus.component.auth.SystemCredentials; import com.eucalyptus.component.id.Euare; import com.eucalyptus.entities.Entities; import com.eucalyptus.entities.TransactionException; import com.eucalyptus.entities.TransactionResource; import com.eucalyptus.util.CollectionUtils; import com.eucalyptus.auth.principal.OwnerFullName; import com.google.common.base.Optional; import com.google.common.base.Strings; import com.google.common.collect.Iterables; /** * */ @ComponentNamed("localPrincipalProvider") public class DatabasePrincipalProvider implements PrincipalProvider { @Override public UserPrincipal lookupPrincipalByUserId(final String userId, final String nonce) throws AuthException { try (final TransactionResource tx = Entities.readOnlyDistinctTransactionFor(UserEntity.class)) { try { final UserEntity user = DatabaseAuthUtils.getUnique(UserEntity.class, "userId", userId); return decorateCredentials(new UserPrincipalImpl(user), nonce, user.getToken()); } catch (Exception e) { throw new AuthException(AuthException.NO_SUCH_USER, e); } } } @Override public UserPrincipal lookupPrincipalByRoleId(final String roleId, final String nonce) throws AuthException { try (final TransactionResource tx = Entities.readOnlyDistinctTransactionFor(RoleEntity.class)) { final EuareRole role = Accounts.lookupRoleById(roleId); return decorateCredentials(Accounts.roleAsPrincipal(role), nonce, role.getSecret()); } } @Override public UserPrincipal lookupPrincipalByAccessKeyId(final String keyId, final String nonce) throws AuthException { try (final TransactionResource tx = Entities.readOnlyDistinctTransactionFor(AccessKeyEntity.class)) { final UserEntity user; try { user = (UserEntity) Entities.createCriteria(UserEntity.class).createCriteria("keys") .add(Restrictions.eq("accessKey", keyId)).setFlushMode(FlushMode.MANUAL).setReadOnly(true) .uniqueResult(); } catch (Exception e) { throw new InvalidAccessKeyAuthException("Failed to find access key", e); } if (user == null) { throw new InvalidAccessKeyAuthException("Failed to find access key"); } final UserPrincipal principal = new UserPrincipalImpl(user); final Optional<AccessKey> accessKey = Iterables.tryFind(principal.getKeys(), CollectionUtils.propertyPredicate(keyId, AccessKeys.accessKeyIdentifier())); if (!Iterables.any(accessKey.asSet(), AccessKeys.isActive())) { throw new InvalidAccessKeyAuthException("Invalid access key or token"); } return decorateCredentials(principal, nonce, accessKey.get().getSecretKey()); } } @Override public UserPrincipal lookupPrincipalByCertificateId(final String certificateId) throws AuthException { try (final TransactionResource tx = Entities.readOnlyDistinctTransactionFor(CertificateEntity.class)) { final Certificate certificate = Accounts.lookupCertificateByHashId(certificateId); if (!certificate.isActive()) { throw new AuthException("Certificate is inactive or revoked: " + certificate.getX509Certificate().getSubjectX500Principal()); } return certificate.getPrincipal(); } } @Override public UserPrincipal lookupPrincipalByCanonicalId(final String canonicalId) throws AuthException { try (final TransactionResource tx = Entities.readOnlyDistinctTransactionFor(UserEntity.class)) { return Accounts.userAsPrincipal(Accounts.lookupAccountByCanonicalId(canonicalId).lookupAdmin()); } } @Override public UserPrincipal lookupPrincipalByAccountNumber(final String accountNumber) throws AuthException { try (final TransactionResource tx = Entities.readOnlyDistinctTransactionFor(UserEntity.class)) { return Accounts.userAsPrincipal(Accounts.lookupAccountById(accountNumber).lookupAdmin()); } } @Override public UserPrincipal lookupPrincipalByAccountNumberAndUsername(final String accountNumber, final String name) throws AuthException { try (final TransactionResource tx = Entities.readOnlyDistinctTransactionFor(UserEntity.class)) { return Accounts.userAsPrincipal(Accounts.lookupAccountById(accountNumber).lookupUserByName(name)); } } @Override public UserPrincipal lookupCachedPrincipalByUserId(final UserPrincipal cached, final String userId, final String nonce) throws AuthException { return lookupPrincipalByUserId(userId, nonce); } @Override public UserPrincipal lookupCachedPrincipalByRoleId(final UserPrincipal cached, final String roleId, final String nonce) throws AuthException { return lookupPrincipalByRoleId(roleId, nonce); } @Override public UserPrincipal lookupCachedPrincipalByAccessKeyId(final UserPrincipal cached, final String keyId, final String nonce) throws AuthException { return lookupPrincipalByAccessKeyId(keyId, nonce); } @Override public UserPrincipal lookupCachedPrincipalByCertificateId(final UserPrincipal cached, final String certificateId) throws AuthException { return lookupPrincipalByCertificateId(certificateId); } @Override public UserPrincipal lookupCachedPrincipalByAccountNumber(final UserPrincipal cached, final String accountNumber) throws AuthException { return lookupPrincipalByAccountNumber(accountNumber); } @Override public AccountIdentifiers lookupAccountIdentifiersByAlias(final String alias) throws AuthException { try (final TransactionResource tx = Entities.readOnlyDistinctTransactionFor(AccountEntity.class)) { return Accounts.lookupAccountByName(alias); } } @Override public AccountIdentifiers lookupAccountIdentifiersByCanonicalId(final String canonicalId) throws AuthException { try (final TransactionResource tx = Entities.readOnlyDistinctTransactionFor(AccountEntity.class)) { return Accounts.lookupAccountByCanonicalId(canonicalId); } } @Override public AccountIdentifiers lookupAccountIdentifiersByEmail(final String email) throws AuthException { try (final TransactionResource tx = Entities.readOnlyDistinctTransactionFor(UserEntity.class)) { final EuareUser euareUser = Accounts.lookupUserByEmailAddress(email); if (euareUser.isAccountAdmin()) { return euareUser.getAccount(); } throw new AuthException(AuthException.NO_SUCH_USER); } } @Override public List<AccountIdentifiers> listAccountIdentifiersByAliasMatch(final String aliasExpression) throws AuthException { try (final TransactionResource tx = Entities.readOnlyDistinctTransactionFor(AccountEntity.class)) { return Accounts.resolveAccountNumbersForName(aliasExpression); } } @Override public InstanceProfile lookupInstanceProfileByName(final String accountNumber, final String name) throws AuthException { try (final TransactionResource tx = Entities.readOnlyDistinctTransactionFor(InstanceProfileEntity.class)) { final EuareInstanceProfile profile = Accounts.lookupAccountById(accountNumber) .lookupInstanceProfileByName(name); final String profileArn = Accounts.getInstanceProfileArn(profile); final EuareRole euareRole = profile.getRole(); final String roleArn = euareRole == null ? null : Accounts.getRoleArn(euareRole); final String roleAccountNumber = euareRole == null ? null : euareRole.getAccountNumber(); final PolicyVersion rolePolicy = euareRole == null ? null : euareRole.getPolicy(); final Role role = euareRole == null ? null : new Role() { @Override public String getAccountNumber() { return roleAccountNumber; } @Override public String getRoleId() { return euareRole.getRoleId(); } @Override public String getRoleArn() { return roleArn; } @Override public String getPath() { return euareRole.getPath(); } @Override public String getName() { return euareRole.getName(); } @Override public String getSecret() { return euareRole.getSecret(); } @Override public PolicyVersion getPolicy() { return rolePolicy; } @Override public String getDisplayName() { return Accounts.getRoleFullName(this); } @Override public OwnerFullName getOwner() { return euareRole.getOwner(); } }; return new InstanceProfile() { @Override public String getAccountNumber() { return accountNumber; } @Override public String getInstanceProfileId() { return profile.getInstanceProfileId(); } @Override public String getInstanceProfileArn() { return profileArn; } @Nullable @Override public Role getRole() { return role; } @Override public String getName() { return profile.getName(); } @Override public String getPath() { return profile.getPath(); } }; } } @Override public Role lookupRoleByName(final String accountNumber, final String name) throws AuthException { try (final TransactionResource tx = Entities.readOnlyDistinctTransactionFor(RoleEntity.class)) { final EuareRole euareRole = Accounts.lookupAccountById(accountNumber).lookupRoleByName(name); final String roleArn = Accounts.getRoleArn(euareRole); final String roleAccountNumber = euareRole.getAccountNumber(); final PolicyVersion assumeRolePolicy = euareRole.getPolicy(); return new Role() { @Override public String getAccountNumber() { return roleAccountNumber; } @Override public String getRoleId() { return euareRole.getRoleId(); } @Override public String getRoleArn() { return roleArn; } @Override public String getPath() { return euareRole.getPath(); } @Override public String getName() { return euareRole.getName(); } @Override public String getSecret() { return euareRole.getSecret(); } @Override public PolicyVersion getPolicy() { return assumeRolePolicy; } @Override public String getDisplayName() { return Accounts.getRoleFullName(this); } @Override public OwnerFullName getOwner() { return euareRole.getOwner(); } }; } } @Override public SecurityTokenContent decodeSecurityToken(final String accessKeyIdentifier, final String securityToken) throws AuthException { return SecurityTokenManager.decodeSecurityToken(accessKeyIdentifier, securityToken); } private UserPrincipal decorateCredentials(final UserPrincipal userPrincipal, final String nonce, final String secret) throws AuthException { final UserPrincipal decorated; if (nonce == null) { decorated = userPrincipal; } else { final String secretKey = SecurityTokenManager.generateSecret(nonce, secret); final Collection<AccessKey> keys = Collections.<AccessKey>singleton(new AccessKey() { @Override public Boolean isActive() { return true; } @Override public String getAccessKey() { return null; } @Override public String getSecretKey() { return secretKey; } @Override public Date getCreateDate() { return null; } @Override public UserPrincipal getPrincipal() { return null; } }); decorated = new UserPrincipalImpl(userPrincipal, keys); } return decorated; } @Override public void reserveGlobalName(final String namespace, final String name, final Integer duration, final String clientToken) throws AuthException { final GlobalNamespace globalNamespace; try { globalNamespace = GlobalNamespace.forNamespace(namespace); } catch (IllegalArgumentException e) { throw new AuthException(e); } if (duration == null || duration < 1 || duration > TimeUnit.DAYS.toSeconds(1)) { throw new AuthException("Requested duration not supported: " + duration); } try (final TransactionResource tx = Entities.transactionFor(ReservedNameEntity.class)) { Entities.persist( ReservedNameEntity.create(namespace, name, duration, Strings.emptyToNull(clientToken))); tx.commit(); } catch (ConstraintViolationException e) { boolean conflict = true; if (!Strings.isNullOrEmpty(clientToken)) try (final TransactionResource tx = Entities .readOnlyDistinctTransactionFor(ReservedNameEntity.class)) { // use the existing reservation for the token if it matches and // has half the duration remaining final ReservedNameEntity entity = Entities .uniqueResult(ReservedNameEntity.exampleWithToken(clientToken)); conflict = !entity.getNamespace().equals(namespace) || !entity.getName().equals(name) || entity.getExpiry().before( new Date(System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(duration / 2))); } catch (TransactionException | NoSuchElementException e1) { // fail with conflict } if (conflict) { throw new AuthException(AuthException.CONFLICT); } } catch (final Exception e) { throw new AuthException(e); } switch (globalNamespace) { case Account_Alias: try { Accounts.lookupAccountByName(name); throw new AuthException(AuthException.CONFLICT); } catch (AuthException e) { if (!AuthException.NO_SUCH_ACCOUNT.equals(e.getMessage())) { throw new AuthException(AuthException.CONFLICT); } } break; case Signing_Certificate_Id: try { Accounts.lookupCertificateById(name); throw new AuthException(AuthException.CONFLICT); } catch (AuthException e) { if (!AuthException.NO_SUCH_CERTIFICATE.equals(e.getMessage())) { throw new AuthException(AuthException.CONFLICT); } } break; default: throw new AuthException(AuthException.CONFLICT); } } @Override public X509Certificate getCertificateByAccountNumber(final String accountNumber) { return SystemCredentials.lookup(Euare.class).getCertificate(); } @Override public X509Certificate signCertificate(final String accountNumber, final RSAPublicKey publicKey, final String principal, final int expiryInDays) throws AuthException { return EuareServerCertificateUtil.generateVMCertificate(publicKey, principal, expiryInDays); } }