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. * * This file may incorporate work covered under the following copyright * and permission notice: * * Software License Agreement (BSD License) * * Copyright (c) 2008, Regents of the University of California * All rights reserved. * * Redistribution and use of this software in source and binary forms, * with or without modification, are permitted provided that the * following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. USERS OF THIS SOFTWARE ACKNOWLEDGE * THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE LICENSED MATERIAL, * COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS SOFTWARE, * AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING * IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, * SANTA BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, * WHICH IN THE REGENTS' DISCRETION MAY INCLUDE, WITHOUT LIMITATION, * REPLACEMENT OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO * IDENTIFIED, OR WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT * NEEDED TO COMPLY WITH ANY SUCH LICENSES OR RIGHTS. ************************************************************************/ package com.eucalyptus.auth.euare.persist; import java.security.MessageDigest; import java.security.PublicKey; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import org.apache.log4j.Logger; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Base64; import org.hibernate.criterion.Restrictions; import com.eucalyptus.auth.Accounts; import com.eucalyptus.auth.AuthException; import com.eucalyptus.auth.AuthenticationLimitProvider; import com.eucalyptus.auth.Debugging; import com.eucalyptus.auth.PolicyParseException; import com.eucalyptus.auth.ServerCertificate; import com.eucalyptus.auth.euare.ServerCertificates; import com.eucalyptus.auth.euare.checker.InvalidValueException; import com.eucalyptus.auth.euare.checker.ValueChecker; import com.eucalyptus.auth.euare.checker.ValueCheckerFactory; import com.eucalyptus.auth.euare.persist.entities.AccountEntity; import com.eucalyptus.auth.euare.persist.entities.CertificateEntity; import com.eucalyptus.auth.euare.persist.entities.GroupEntity; import com.eucalyptus.auth.euare.persist.entities.InstanceProfileEntity; import com.eucalyptus.auth.euare.persist.entities.PolicyEntity; import com.eucalyptus.auth.euare.persist.entities.RoleEntity; import com.eucalyptus.auth.euare.persist.entities.ServerCertificateEntity; import com.eucalyptus.auth.euare.persist.entities.UserEntity; import com.eucalyptus.auth.euare.principal.EuareAccount; import com.eucalyptus.auth.euare.principal.EuareGroup; import com.eucalyptus.auth.euare.principal.EuareRole; import com.eucalyptus.auth.euare.principal.EuareUser; import com.eucalyptus.auth.policy.PolicyParser; import com.eucalyptus.auth.policy.PolicyPolicy; import com.eucalyptus.auth.principal.AccountFullName; import com.eucalyptus.auth.euare.principal.EuareInstanceProfile; import com.eucalyptus.auth.principal.User; import com.eucalyptus.auth.principal.UserFullName; import com.eucalyptus.auth.util.Identifiers; import com.eucalyptus.component.auth.SystemCredentials; import com.eucalyptus.component.id.Euare; import com.eucalyptus.crypto.Ciphers; import com.eucalyptus.crypto.Crypto; import com.eucalyptus.crypto.Digest; import com.eucalyptus.entities.Entities; import com.eucalyptus.entities.TransactionResource; import com.eucalyptus.util.Exceptions; import com.eucalyptus.auth.principal.OwnerFullName; import com.eucalyptus.util.Tx; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.base.Suppliers; import com.google.common.collect.Collections2; import com.google.common.collect.Lists; import com.google.common.collect.Maps; public class DatabaseAccountProxy implements EuareAccount { private static final long serialVersionUID = 1L; private static Logger LOG = Logger.getLogger(DatabaseAccountProxy.class); private static final ValueChecker ACCOUNT_NAME_CHECKER = ValueCheckerFactory.createAccountNameChecker(); private static final ValueChecker USER_GROUP_NAME_CHECKER = ValueCheckerFactory.createUserAndGroupNameChecker(); private static final ValueChecker PATH_CHECKER = ValueCheckerFactory.createPathChecker(); private AccountEntity delegate; public DatabaseAccountProxy(AccountEntity delegate) { this.delegate = delegate; } private static Map<String, Object> lockMap = Maps.newHashMap(); private static synchronized Object obtainLock(final String key) { if (!lockMap.containsKey(key)) lockMap.put(key, new Object()); return lockMap.get(key); } private Object getLock() { return obtainLock(this.getAccountNumber()); } @Override public String getName() { return this.delegate.getName(); } /** * Get the resource display name, this is the name with path. * * @return The display name. */ @Override public String getDisplayName() { return Accounts.getAccountFullName(this); } @Override public OwnerFullName getOwner() { return AccountFullName.getInstance(getAccountNumber()); } @Override public String toString() { return this.delegate.toString(); } public boolean hasAccountAlias() { return !getAccountNumber().equals(getName()); } @Override public String getAccountNumber() { return this.delegate.getAccountNumber(); } @Override public String getAccountAlias() { return getName(); } @Override public String getCanonicalId() { return this.delegate.getCanonicalId(); } @Override public void setName(final String name) throws AuthException { try { ACCOUNT_NAME_CHECKER.check(name); } catch (InvalidValueException e) { Debugging.logError(LOG, e, "Invalid account name " + name); throw new AuthException(AuthException.INVALID_NAME, e); } setNameUnsafe(name); } @Override public void setNameUnsafe(final String name) throws AuthException { try { // try finding the account with the same name to change to (new DatabaseAuthProvider()).lookupAccountByName(name); } catch (AuthException ae) { try { // not found DatabaseAuthUtils.invokeUnique(AccountEntity.class, "accountNumber", this.delegate.getAccountNumber(), new Tx<AccountEntity>() { public void fire(AccountEntity t) { t.setName(name); } }); } catch (Exception e) { Debugging.logError(LOG, e, "Failed to setName for " + this.delegate); throw new AuthException(e); } return; } // found throw new AuthException(AuthException.ACCOUNT_ALREADY_EXISTS); } @Override public List<EuareUser> getUsers() throws AuthException { List<EuareUser> results = Lists.newArrayList(); try (final TransactionResource db = Entities.transactionFor(GroupEntity.class)) { @SuppressWarnings("unchecked") List<UserEntity> users = (List<UserEntity>) Entities.createCriteria(UserEntity.class).setCacheable(true) .createCriteria("groups").setCacheable(true).add(Restrictions.eq("userGroup", true)) .createCriteria("account").setCacheable(true) .add(Restrictions.eq("name", this.delegate.getName())).list(); db.commit(); for (UserEntity u : users) { results.add(new DatabaseUserProxy(u)); } return results; } catch (Exception e) { Debugging.logError(LOG, e, "Failed to get users for " + this.delegate.getName()); throw new AuthException("Failed to get users for account", e); } } @Override public List<EuareGroup> getGroups() throws AuthException { List<EuareGroup> results = Lists.newArrayList(); try (final TransactionResource db = Entities.transactionFor(GroupEntity.class)) { @SuppressWarnings("unchecked") List<GroupEntity> groups = (List<GroupEntity>) Entities.createCriteria(GroupEntity.class) .setCacheable(true).add(Restrictions.eq("userGroup", false)).createCriteria("account") .setCacheable(true).add(Restrictions.eq("name", this.delegate.getName())).list(); db.commit(); for (GroupEntity g : groups) { results.add(new DatabaseGroupProxy(g, Suppliers.ofInstance(getAccountNumber()))); } return results; } catch (Exception e) { Debugging.logError(LOG, e, "Failed to get groups for " + this.delegate.getName()); throw new AuthException("Failed to get groups", e); } } @Override public List<EuareRole> getRoles() throws AuthException { final List<EuareRole> results = Lists.newArrayList(); try (final TransactionResource db = Entities.transactionFor(RoleEntity.class)) { @SuppressWarnings("unchecked") List<RoleEntity> roles = (List<RoleEntity>) Entities.createCriteria(RoleEntity.class) .createCriteria("account").add(Restrictions.eq("name", this.delegate.getName())) .setCacheable(true).list(); for (final RoleEntity role : roles) { results.add(new DatabaseRoleProxy(role)); } return results; } catch (Exception e) { Debugging.logError(LOG, e, "Failed to get roles for " + this.delegate.getName()); throw new AuthException("Failed to get roles", e); } } @Override public List<EuareInstanceProfile> getInstanceProfiles() throws AuthException { final List<EuareInstanceProfile> results = Lists.newArrayList(); try (final TransactionResource db = Entities.transactionFor(InstanceProfileEntity.class)) { @SuppressWarnings("unchecked") List<InstanceProfileEntity> instanceProfiles = (List<InstanceProfileEntity>) Entities .createCriteria(InstanceProfileEntity.class).createCriteria("account") .add(Restrictions.eq("name", this.delegate.getName())).setCacheable(true).list(); for (final InstanceProfileEntity instanceProfile : instanceProfiles) { results.add(new DatabaseInstanceProfileProxy(instanceProfile)); } return results; } catch (Exception e) { Debugging.logError(LOG, e, "Failed to get instance profiles for " + this.delegate.getName()); throw new AuthException("Failed to get instance profiles", e); } } @Override public EuareUser addUser(String userName, String path, boolean enabled, Map<String, String> info) throws AuthException { synchronized (getLock()) { try { USER_GROUP_NAME_CHECKER.check(userName); } catch (InvalidValueException e) { Debugging.logError(LOG, e, "Invalid user name " + userName); throw new AuthException(AuthException.INVALID_NAME, e); } try { PATH_CHECKER.check(path); } catch (InvalidValueException e) { Debugging.logError(LOG, e, "Invalid path " + path); throw new AuthException(AuthException.INVALID_PATH, e); } if (DatabaseAuthUtils.checkUserExists(userName, this.delegate.getName())) { throw new AuthException(AuthException.USER_ALREADY_EXISTS); } UserEntity newUser = new UserEntity(this.getAccountNumber(), userName); newUser.setPath(path); newUser.setEnabled(enabled); newUser.setPasswordExpires( System.currentTimeMillis() + AuthenticationLimitProvider.Values.getDefaultPasswordExpiry()); if (info != null) { newUser.getInfo().putAll(info); } newUser.setToken(Crypto.generateSessionToken()); //newUser.setConfirmationCode( Crypto.generateSessionToken( userName ) ); GroupEntity newGroup = new GroupEntity(this.getAccountNumber(), DatabaseAuthUtils.getUserGroupName(userName)); newGroup.setUserGroup(true); try (final TransactionResource db = Entities.transactionFor(AccountEntity.class)) { AccountEntity account = DatabaseAuthUtils.getUnique(AccountEntity.class, "name", this.delegate.getName()); newGroup = Entities.mergeDirect(newGroup); newUser = Entities.mergeDirect(newUser); newGroup.setAccount(account); newGroup.getUsers().add(newUser); newUser.getGroups().add(newGroup); db.commit(); return new DatabaseUserProxy(newUser); } catch (Exception e) { Debugging.logError(LOG, e, "Failed to add user: " + userName + " in " + this.delegate.getName()); throw new AuthException(AuthException.USER_CREATE_FAILURE, e); } } } private boolean userHasResourceAttached(String userName, String accountName) throws AuthException { try (final TransactionResource db = Entities.transactionFor(UserEntity.class)) { UserEntity user = DatabaseAuthUtils.getUniqueUser(userName, accountName); GroupEntity userGroup = DatabaseAuthUtils.getUniqueGroup(DatabaseAuthUtils.getUserGroupName(userName), accountName); boolean result = (user.getGroups().size() > 1 || user.getKeys().size() > 0 || user.getCertificates().size() > 0 || userGroup.getPolicies().size() > 0); db.commit(); return result; } catch (Exception e) { Debugging.logError(LOG, e, "Failed to check user " + userName + " in " + accountName); throw new AuthException(AuthException.NO_SUCH_USER, e); } } private boolean roleHasResourceAttached(String roleName, String accountName) throws AuthException { try (final TransactionResource db = Entities.transactionFor(RoleEntity.class)) { final RoleEntity roleEntity = DatabaseAuthUtils.getUniqueRole(roleName, accountName); return !roleEntity.getPolicies().isEmpty() || !roleEntity.getInstanceProfiles().isEmpty(); } catch (Exception e) { Debugging.logError(LOG, e, "Failed to check role " + roleName + " in " + accountName); throw new AuthException(AuthException.NO_SUCH_ROLE, e); } } @Override public void deleteUser(String userName, boolean forceDeleteAdmin, boolean recursive) throws AuthException { synchronized (getLock()) { String accountName = this.delegate.getName(); if (userName == null) { throw new AuthException(AuthException.EMPTY_USER_NAME); } if (!forceDeleteAdmin && DatabaseAuthUtils.isAccountAdmin(userName)) { throw new AuthException(AuthException.DELETE_ACCOUNT_ADMIN); } if (!recursive && userHasResourceAttached(userName, accountName)) { throw new AuthException(AuthException.USER_DELETE_CONFLICT); } try (final TransactionResource db = Entities.transactionFor(UserEntity.class)) { UserEntity user = DatabaseAuthUtils.getUniqueUser(userName, accountName); for (GroupEntity ge : user.getGroups()) { if (ge.isUserGroup()) { Entities.delete(ge); } else { ge.getUsers().remove(user); } } Entities.delete(user); db.commit(); } catch (Exception e) { Debugging.logError(LOG, e, "Failed to delete user: " + userName + " in " + accountName); throw new AuthException(AuthException.NO_SUCH_USER, e); } } } @Override public EuareRole addRole(final String roleName, final String path, final String assumeRolePolicy) throws AuthException, PolicyParseException { synchronized (getLock()) { try { USER_GROUP_NAME_CHECKER.check(roleName); } catch (InvalidValueException e) { Debugging.logError(LOG, e, "Invalid role name " + roleName); throw new AuthException(AuthException.INVALID_NAME, e); } try { PATH_CHECKER.check(path); } catch (InvalidValueException e) { Debugging.logError(LOG, e, "Invalid path " + path); throw new AuthException(AuthException.INVALID_PATH, e); } if (DatabaseAuthUtils.checkRoleExists(roleName, this.delegate.getName())) { throw new AuthException(AuthException.ROLE_ALREADY_EXISTS); } final PolicyPolicy policyPolicy = PolicyParser.getResourceInstance().parse(assumeRolePolicy); final PolicyEntity parsedPolicy = PolicyEntity.create(null, policyPolicy.getPolicyVersion(), assumeRolePolicy); try (final TransactionResource db = Entities.transactionFor(AccountEntity.class)) { final AccountEntity account = DatabaseAuthUtils.getUnique(AccountEntity.class, "name", this.delegate.getName()); final RoleEntity newRole = new RoleEntity(roleName); newRole.setRoleId(Identifiers.generateIdentifier("ARO")); newRole.setPath(path); newRole.setAccount(account); newRole.setAssumeRolePolicy(parsedPolicy); parsedPolicy.setName("assume-role-policy-for-" + newRole.getRoleId()); final RoleEntity persistedRole = Entities.persist(newRole); db.commit(); return new DatabaseRoleProxy(persistedRole); } catch (Exception e) { Debugging.logError(LOG, e, "Failed to add role: " + roleName + " in " + this.delegate.getName()); throw new AuthException(AuthException.ROLE_CREATE_FAILURE, e); } } } @Override public void deleteRole(final String roleName) throws AuthException { synchronized (getLock()) { final String accountName = this.delegate.getName(); if (roleName == null) { throw new AuthException(AuthException.EMPTY_ROLE_NAME); } if (roleHasResourceAttached(roleName, accountName)) { throw new AuthException(AuthException.ROLE_DELETE_CONFLICT); } try (final TransactionResource db = Entities.transactionFor(RoleEntity.class)) { final RoleEntity role = DatabaseAuthUtils.getUniqueRole(roleName, accountName); Entities.delete(role); db.commit(); } catch (Exception e) { Debugging.logError(LOG, e, "Failed to delete role: " + roleName + " in " + accountName); throw new AuthException(AuthException.NO_SUCH_ROLE, e); } } } @Override public EuareGroup addGroup(String groupName, String path) throws AuthException { synchronized (getLock()) { try { USER_GROUP_NAME_CHECKER.check(groupName); } catch (InvalidValueException e) { Debugging.logError(LOG, e, "Invalid group name " + groupName); throw new AuthException(AuthException.INVALID_NAME, e); } try { PATH_CHECKER.check(path); } catch (InvalidValueException e) { Debugging.logError(LOG, e, "Invalid path " + path); throw new AuthException(AuthException.INVALID_PATH, e); } if (DatabaseAuthUtils.checkGroupExists(groupName, this.delegate.getName())) { throw new AuthException(AuthException.GROUP_ALREADY_EXISTS); } try (final TransactionResource db = Entities.transactionFor(AccountEntity.class)) { AccountEntity account = DatabaseAuthUtils.getUnique(AccountEntity.class, "name", this.delegate.getName()); GroupEntity group = new GroupEntity(this.getAccountNumber(), groupName); group.setPath(path); group.setUserGroup(false); group.setAccount(account); Entities.persist(group); db.commit(); return new DatabaseGroupProxy(group, Suppliers.ofInstance(getAccountNumber())); } catch (Exception e) { Debugging.logError(LOG, e, "Failed to add group " + groupName + " in " + this.delegate.getName()); throw new AuthException(AuthException.GROUP_CREATE_FAILURE, e); } } } private boolean groupHasResourceAttached(String groupName, String accountName) throws AuthException { try (final TransactionResource db = Entities.transactionFor(GroupEntity.class)) { GroupEntity group = DatabaseAuthUtils.getUniqueGroup(groupName, accountName); boolean hasResAttached = group.getUsers().size() > 0 || group.getPolicies().size() > 0; db.commit(); return hasResAttached; } catch (Exception e) { Debugging.logError(LOG, e, "Failed to check group " + groupName + " in " + accountName); throw new AuthException(AuthException.NO_SUCH_GROUP, e); } } @Override public void deleteGroup(String groupName, boolean recursive) throws AuthException { synchronized (getLock()) { String accountName = this.delegate.getName(); if (groupName == null) { throw new AuthException(AuthException.EMPTY_GROUP_NAME); } if (DatabaseAuthUtils.isUserGroupName(groupName)) { throw new AuthException(AuthException.USER_GROUP_DELETE); } if (!recursive && groupHasResourceAttached(groupName, accountName)) { throw new AuthException(AuthException.GROUP_DELETE_CONFLICT); } try (final TransactionResource db = Entities.transactionFor(GroupEntity.class)) { GroupEntity group = DatabaseAuthUtils.getUniqueGroup(groupName, accountName); Entities.delete(group); db.commit(); } catch (Exception e) { Debugging.logError(LOG, e, "Failed to delete group " + groupName + " in " + accountName); throw new AuthException(AuthException.NO_SUCH_GROUP, e); } } } @Override public EuareInstanceProfile addInstanceProfile(final String instanceProfileName, final String path) throws AuthException { synchronized (getLock()) { try { USER_GROUP_NAME_CHECKER.check(instanceProfileName); } catch (InvalidValueException e) { Debugging.logError(LOG, e, "Invalid instance profile name " + instanceProfileName); throw new AuthException(AuthException.INVALID_NAME, e); } try { PATH_CHECKER.check(path); } catch (InvalidValueException e) { Debugging.logError(LOG, e, "Invalid path " + path); throw new AuthException(AuthException.INVALID_PATH, e); } if (DatabaseAuthUtils.checkInstanceProfileExists(instanceProfileName, this.delegate.getName())) { throw new AuthException(AuthException.INSTANCE_PROFILE_ALREADY_EXISTS); } try (final TransactionResource db = Entities.transactionFor(AccountEntity.class)) { final AccountEntity account = DatabaseAuthUtils.getUnique(AccountEntity.class, "name", this.delegate.getName()); final InstanceProfileEntity newInstanceProfile = new InstanceProfileEntity(instanceProfileName); newInstanceProfile.setPath(path); newInstanceProfile.setAccount(account); final InstanceProfileEntity persistedInstanceProfile = Entities.persist(newInstanceProfile); db.commit(); return new DatabaseInstanceProfileProxy(persistedInstanceProfile); } catch (Exception e) { Debugging.logError(LOG, e, "Failed to add instance profile: " + instanceProfileName + " in " + this.delegate.getName()); throw new AuthException(AuthException.INSTANCE_PROFILE_CREATE_FAILURE, e); } } } @Override public void deleteInstanceProfile(final String instanceProfileName) throws AuthException { synchronized (getLock()) { final String accountName = this.delegate.getName(); if (instanceProfileName == null) { throw new AuthException(AuthException.EMPTY_INSTANCE_PROFILE_NAME); } try (final TransactionResource db = Entities.transactionFor(InstanceProfileEntity.class)) { final InstanceProfileEntity instanceProfileEntity = DatabaseAuthUtils .getUniqueInstanceProfile(instanceProfileName, accountName); Entities.delete(instanceProfileEntity); db.commit(); } catch (Exception e) { Debugging.logError(LOG, e, "Failed to delete instance profile: " + instanceProfileName + " in " + accountName); throw new AuthException(AuthException.NO_SUCH_INSTANCE_PROFILE, e); } } } @Override public EuareGroup lookupGroupByName(String groupName) throws AuthException { String accountName = this.delegate.getName(); if (groupName == null) { throw new AuthException(AuthException.EMPTY_GROUP_NAME); } try (final TransactionResource db = Entities.transactionFor(GroupEntity.class)) { GroupEntity group = DatabaseAuthUtils.getUniqueGroup(groupName, accountName); db.commit(); return new DatabaseGroupProxy(group, Suppliers.ofInstance(getAccountNumber())); } catch (Exception e) { Debugging.logError(LOG, e, "Failed to get group " + groupName + " for " + accountName); throw new AuthException(AuthException.NO_SUCH_GROUP, e); } } @Override public EuareInstanceProfile lookupInstanceProfileByName(final String instanceProfileName) throws AuthException { final String accountName = this.delegate.getName(); if (instanceProfileName == null) { throw new AuthException(AuthException.EMPTY_INSTANCE_PROFILE_NAME); } try (final TransactionResource db = Entities.transactionFor(InstanceProfileEntity.class)) { final InstanceProfileEntity instanceProfileEntity = DatabaseAuthUtils .getUniqueInstanceProfile(instanceProfileName, accountName); return new DatabaseInstanceProfileProxy(instanceProfileEntity); } catch (Exception e) { Debugging.logError(LOG, e, "Failed to get instance profile " + instanceProfileName + " for " + accountName); throw new AuthException(AuthException.NO_SUCH_INSTANCE_PROFILE, e); } } @Override public EuareRole lookupRoleByName(String roleName) throws AuthException { final String accountName = this.delegate.getName(); if (roleName == null) { throw new AuthException(AuthException.EMPTY_ROLE_NAME); } try (final TransactionResource db = Entities.transactionFor(RoleEntity.class)) { final RoleEntity roleEntity = DatabaseAuthUtils.getUniqueRole(roleName, accountName); return new DatabaseRoleProxy(roleEntity); } catch (Exception e) { Debugging.logError(LOG, e, "Failed to get role " + roleName + " for " + accountName); throw new AuthException(AuthException.NO_SUCH_ROLE, e); } } @Override public EuareUser lookupUserByName(String userName) throws AuthException { String accountName = this.delegate.getName(); if (userName == null) { throw new AuthException(AuthException.EMPTY_USER_NAME); } try (final TransactionResource db = Entities.transactionFor(UserEntity.class)) { UserEntity user = DatabaseAuthUtils.getUniqueUser(userName, accountName); db.commit(); return new DatabaseUserProxy(user); } catch (Exception e) { Debugging.logError(LOG, e, "Failed to find user: " + userName + " in " + accountName); throw new AuthException(AuthException.NO_SUCH_USER, e); } } @Override public EuareUser lookupAdmin() throws AuthException { return lookupUserByName(User.ACCOUNT_ADMIN); } @Override public ServerCertificate addServerCertificate(String certName, String certBody, String certChain, String certPath, String pk) throws AuthException { synchronized (getLock()) { if (!ServerCertificateEntity.isCertificateNameValid(certName)) throw new AuthException(AuthException.INVALID_SERVER_CERT_NAME); if (!ServerCertificateEntity.isCertificatePathValid(certPath)) throw new AuthException(AuthException.INVALID_SERVER_CERT_PATH); try { ServerCertificates.verifyCertificate(certBody, pk, certChain); } catch (final AuthException ex) { throw ex; } catch (final Exception ex) { throw new AuthException(AuthException.SERVER_CERT_INVALID_FORMAT); } String encPk = null; String sessionKey = null; try { // generate symmetric key final MessageDigest digest = Digest.SHA256.get(); final byte[] salt = new byte[32]; Crypto.getSecureRandomSupplier().get().nextBytes(salt); //digest.update( this.lookupAdmin().getPassword().getBytes( Charsets.UTF_8 ) ); digest.update(salt); final SecretKey symmKey = new SecretKeySpec(digest.digest(), "AES"); // encrypt the server pk Cipher cipher = Ciphers.AES_GCM.get(); final byte[] iv = new byte[32]; Crypto.getSecureRandomSupplier().get().nextBytes(iv); cipher.init(Cipher.ENCRYPT_MODE, symmKey, new IvParameterSpec(iv), Crypto.getSecureRandomSupplier().get()); final byte[] cipherText = cipher.doFinal(pk.getBytes()); encPk = new String(Base64.encode(Arrays.concatenate(iv, cipherText))); final PublicKey euarePublicKey = SystemCredentials.lookup(Euare.class).getCertificate() .getPublicKey(); cipher = Ciphers.RSA_PKCS1.get(); cipher.init(Cipher.WRAP_MODE, euarePublicKey, Crypto.getSecureRandomSupplier().get()); byte[] wrappedKeyBytes = cipher.wrap(symmKey); sessionKey = new String(Base64.encode(wrappedKeyBytes)); } catch (final Exception e) { LOG.error("Failed to encrypt key", e); throw Exceptions.toUndeclared(e); } try { final ServerCertificate found = lookupServerCertificate(certName); if (found != null) throw new AuthException(AuthException.SERVER_CERT_ALREADY_EXISTS); } catch (final NoSuchElementException ex) { ; } catch (final AuthException ex) { if (!AuthException.SERVER_CERT_NO_SUCH_ENTITY.equals(ex.getMessage())) throw ex; } catch (final Exception ex) { throw ex; } final String certId = Identifiers.generateIdentifier("ASC"); ServerCertificateEntity entity = null; try (final TransactionResource db = Entities.transactionFor(ServerCertificateEntity.class)) { final UserFullName accountAdmin = UserFullName.getInstance(this.lookupAdmin()); entity = new ServerCertificateEntity(accountAdmin, certName); entity.setCertBody(certBody); entity.setCertChain(certChain); entity.setCertPath(certPath); entity.setPrivateKey(encPk); entity.setSessionKey(sessionKey); entity.setCertId(certId); Entities.persist(entity); db.commit(); } catch (final Exception ex) { LOG.error("Failed to persist server certificate entity", ex); throw Exceptions.toUndeclared(ex); } return ServerCertificates.ToServerCertificate.INSTANCE.apply(entity); } } @Override public ServerCertificate deleteServerCertificate(String certName) throws AuthException { synchronized (getLock()) { ServerCertificateEntity found = null; try (final TransactionResource db = Entities.transactionFor(ServerCertificateEntity.class)) { found = Entities.uniqueResult( ServerCertificateEntity.named(UserFullName.getInstance(this.lookupAdmin()), certName)); Entities.delete(found); db.commit(); } catch (final NoSuchElementException ex) { throw new AuthException(AuthException.SERVER_CERT_NO_SUCH_ENTITY); } catch (final Exception ex) { throw Exceptions.toUndeclared(ex); } if (found != null) return ServerCertificates.ToServerCertificate.INSTANCE.apply(found); else return null; } } @Override public ServerCertificate lookupServerCertificate(String certName) throws AuthException { ServerCertificateEntity found = null; try (final TransactionResource db = Entities.transactionFor(ServerCertificateEntity.class)) { final List<ServerCertificateEntity> result = Entities.query( ServerCertificateEntity.named(UserFullName.getInstance(this.lookupAdmin()), certName), true); if (result == null || result.size() <= 0) throw new AuthException(AuthException.SERVER_CERT_NO_SUCH_ENTITY); found = result.get(0); db.rollback(); return ServerCertificates.ToServerCertificate.INSTANCE.apply(found); } catch (final NoSuchElementException ex) { throw new AuthException(AuthException.SERVER_CERT_NO_SUCH_ENTITY); } catch (final AuthException ex) { throw ex; } catch (final Exception ex) { throw Exceptions.toUndeclared(ex); } } @Override public List<ServerCertificate> listServerCertificates(String pathPrefix) throws AuthException { List<ServerCertificateEntity> result = null; try (final TransactionResource db = Entities.transactionFor(ServerCertificateEntity.class)) { result = Entities.query(ServerCertificateEntity.named(UserFullName.getInstance(this.lookupAdmin())), true); db.rollback(); } catch (final Exception ex) { throw Exceptions.toUndeclared(ex); } final String prefix = pathPrefix.length() > 1 && pathPrefix.endsWith("/") ? pathPrefix.substring(0, pathPrefix.length() - 1) : pathPrefix; List<ServerCertificateEntity> filtered = null; if (prefix.equals("/")) { filtered = result; } else { filtered = Lists.newArrayList(Collections2.filter(result, new Predicate<ServerCertificateEntity>() { @Override public boolean apply(ServerCertificateEntity entity) { final String path = entity.getCertPath(); return path.startsWith(prefix) && (path.length() == prefix.length() || path.charAt(prefix.length()) == '/'); } })); } return Lists.transform(filtered, new Function<ServerCertificateEntity, ServerCertificate>() { @Override public ServerCertificate apply(ServerCertificateEntity entity) { return ServerCertificates.ToServerCertificate.INSTANCE.apply(entity); } }); } @Override public void updateServerCeritificate(String certName, String newCertName, String newPath) throws AuthException { synchronized (getLock()) { try { ServerCertificate cert = this.lookupServerCertificate(certName); try { cert = this.lookupServerCertificate(newCertName); if (cert != null) throw new AuthException(AuthException.SERVER_CERT_ALREADY_EXISTS); } catch (final AuthException ex) { ; } ServerCertificates.updateServerCertificate(UserFullName.getInstance(this.lookupAdmin()), certName, newCertName, newPath); } catch (final AuthException ex) { throw ex; } catch (final Exception ex) { throw ex; } } } }