/*************************************************************************
* Copyright 2009-2016 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 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.common.oidc.OIDCIssuerIdentifier;
import com.eucalyptus.auth.euare.common.oidc.OIDCUtils;
import com.eucalyptus.auth.euare.persist.entities.AccountEntity;
import com.eucalyptus.auth.euare.persist.entities.AccountEntity_;
import com.eucalyptus.auth.euare.persist.entities.GroupEntity;
import com.eucalyptus.auth.euare.persist.entities.GroupEntity_;
import com.eucalyptus.auth.euare.persist.entities.InstanceProfileEntity;
import com.eucalyptus.auth.euare.persist.entities.InstanceProfileEntity_;
import com.eucalyptus.auth.euare.persist.entities.ManagedPolicyEntity;
import com.eucalyptus.auth.euare.persist.entities.ManagedPolicyEntity_;
import com.eucalyptus.auth.euare.persist.entities.ManagedPolicyVersionEntity;
import com.eucalyptus.auth.euare.persist.entities.ManagedPolicyVersionEntity_;
import com.eucalyptus.auth.euare.persist.entities.OpenIdProviderEntity;
import com.eucalyptus.auth.euare.persist.entities.OpenIdProviderEntity_;
import com.eucalyptus.auth.euare.persist.entities.PolicyEntity;
import com.eucalyptus.auth.euare.persist.entities.RoleEntity;
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.persist.entities.UserEntity_;
import com.eucalyptus.auth.euare.principal.EuareAccount;
import com.eucalyptus.auth.euare.principal.EuareGroup;
import com.eucalyptus.auth.euare.principal.EuareManagedPolicy;
import com.eucalyptus.auth.euare.principal.EuareOpenIdConnectProvider;
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.Iterables;
import com.google.common.collect.Lists;
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_NAME_CHECKER = ValueCheckerFactory.createUserNameChecker( );
private static final ValueChecker GROUP_NAME_CHECKER = ValueCheckerFactory.createGroupNameChecker( );
private static final ValueChecker MANAGED_POLICY_NAME_CHECKER = ValueCheckerFactory.createManagedPolicyNameChecker( );
private static final ValueChecker PATH_CHECKER = ValueCheckerFactory.createPathChecker( );
private AccountEntity delegate;
public DatabaseAccountProxy( AccountEntity delegate ) {
this.delegate = delegate;
}
@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, AccountEntity_.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 ) ) {
List<UserEntity> users = Entities
.criteriaQuery( UserEntity.class )
.join( UserEntity_.groups ).whereEqual( GroupEntity_.userGroup, Boolean.TRUE )
.join( GroupEntity_.account ).whereEqual( AccountEntity_.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 ) ) {
List<GroupEntity> groups = Entities
.criteriaQuery( GroupEntity.class ).whereEqual( GroupEntity_.userGroup, Boolean.FALSE )
.join( GroupEntity_.account ).whereEqual( AccountEntity_.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 ) ) {
List<RoleEntity> roles = Entities
.criteriaQuery( RoleEntity.class )
.join( RoleEntity_.account ).whereEqual( AccountEntity_.name, this.delegate.getName( ) )
.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 ) ) {
List<InstanceProfileEntity> instanceProfiles = Entities
.criteriaQuery( InstanceProfileEntity.class )
.join( InstanceProfileEntity_.account ).whereEqual( AccountEntity_.name, this.delegate.getName( ) )
.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 List<EuareManagedPolicy> getPolicies( final Boolean attached ) throws AuthException {
final List<EuareManagedPolicy> results = Lists.newArrayList( );
try ( final TransactionResource db = Entities.transactionFor( ManagedPolicyEntity.class ) ) {
List<ManagedPolicyEntity> policies = Entities
.criteriaQuery( ManagedPolicyEntity.class ).where( ManagedPolicyEntity.exampleWithAttachment( attached ) )
.join( ManagedPolicyEntity_.account ).whereEqual( AccountEntity_.name, this.delegate.getName( ) )
.list( );
for ( final ManagedPolicyEntity policy : policies ) {
results.add( new DatabaseManagedPolicyProxy( policy ) );
}
return results;
} catch ( Exception e ) {
Debugging.logError( LOG, e, "Failed to get policies for " + this.delegate.getName( ) );
throw new AuthException( "Failed to get policies", e );
}
}
@Override
public long countPolicies( ) throws AuthException {
try ( final TransactionResource db = Entities.transactionFor( ManagedPolicyEntity.class ) ) {
return Entities.count( ManagedPolicyEntity.class )
.join( ManagedPolicyEntity_.account ).whereEqual( AccountEntity_.name, this.delegate.getName( ) )
.uniqueResult( );
} catch ( Exception e ) {
Debugging.logError( LOG, e, "Failed to count policies for " + this.delegate.getName( ) );
throw new AuthException( "Failed to count policies", e );
}
}
@Override
public EuareUser addUser( String userName, String path, boolean enabled, Map<String, String> info ) throws AuthException {
try {
USER_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, AccountEntity_.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
|| user.getAttachedPolicies( ).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( ) ||
!roleEntity.getAttachedPolicies( ).isEmpty( );
} catch ( Exception e ) {
Debugging.logError( LOG, e, "Failed to check role " + roleName + " in " + accountName );
throw new AuthException( AuthException.NO_SUCH_ROLE, e );
}
}
private boolean policyHasResourceAttached( String policyName, String accountName ) throws AuthException {
try ( final TransactionResource db = Entities.transactionFor( ManagedPolicyEntity.class ) ) {
final ManagedPolicyEntity policyEntity = DatabaseAuthUtils.getUniqueManagedPolicy( policyName, accountName );
return
!policyEntity.getUsers( ).isEmpty( ) ||
!policyEntity.getGroups( ).isEmpty( ) ||
!policyEntity.getRoles( ).isEmpty( );
} catch ( Exception e ) {
Debugging.logError( LOG, e, "Failed to check policy " + policyName + " in " + accountName );
throw new AuthException( AuthException.NO_SUCH_POLICY, e );
}
}
@Override
public void deleteUser( String userName, boolean forceDeleteAdmin, boolean recursive ) throws AuthException {
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 ) ) {
final UserEntity user = DatabaseAuthUtils.getUniqueUser( userName, accountName );
// attachments will be removed, but we need to do the attachment accounting here when delete is recursive
Entities.criteriaQuery( ManagedPolicyEntity.class )
.join( ManagedPolicyEntity_.users ).whereEqual( UserEntity_.name, userName )
.join( UserEntity_.groups ).whereEqual( GroupEntity_.userGroup, true )
.join( GroupEntity_.account ).whereEqual( AccountEntity_.name, accountName )
.list( ).forEach( ManagedPolicyEntity::decrementAttachmentCount );
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 {
try {
USER_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, AccountEntity_.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 {
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 {
try {
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, AccountEntity_.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 ) ) {
boolean hasResAttached =
DatabaseAuthUtils.countUsersInGroup( groupName, accountName ) > 0 ||
DatabaseAuthUtils.countPoliciesInGroup( groupName, accountName ) > 0 ||
DatabaseAuthUtils.countPoliciesAttachedToGroup( groupName, accountName ) > 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 {
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 ) ) {
final GroupEntity group = DatabaseAuthUtils.getUniqueGroup( groupName, accountName );
// attachments will be removed, but we need to do the attachment accounting here when delete is recursive
Entities.criteriaQuery( ManagedPolicyEntity.class )
.join( ManagedPolicyEntity_.groups ).whereEqual( GroupEntity_.name, groupName )
.join( GroupEntity_.account ).whereEqual( AccountEntity_.name, accountName )
.list( ).forEach( ManagedPolicyEntity::decrementAttachmentCount );
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 {
try {
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, AccountEntity_.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 {
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 EuareManagedPolicy addPolicy(
final String policyName,
final String path,
final String description,
final String policy
) throws AuthException {
// validate policy
try {
MANAGED_POLICY_NAME_CHECKER.check( policyName );
} catch ( InvalidValueException e ) {
throw new AuthException( AuthException.INVALID_NAME, e );
}
try {
PATH_CHECKER.check( path );
if ( !path.endsWith( "/" ) ) {
throw new InvalidValueException( );
}
} catch ( InvalidValueException e ) {
throw new AuthException( AuthException.INVALID_PATH, e );
}
if ( description != null && description.length( ) > 1000 ) {
throw new AuthException( AuthException.INVALID_DESCRIPTION );
}
try {
PolicyParser.getInstance( ).parse( policy, "2012-10-17" );
} catch ( final PolicyParseException e ) {
throw new AuthException( "Invalid policy: " + e.getMessage( ) );
}
// check duplicate
if ( DatabaseAuthUtils.checkPolicyExists( policyName, this.delegate.getName() ) ) {
throw new AuthException( AuthException.POLICY_ALREADY_EXISTS );
}
try ( final TransactionResource db = Entities.transactionFor( ManagedPolicyEntity.class ) ) {
final AccountEntity account = DatabaseAuthUtils.getUnique( AccountEntity.class, AccountEntity_.name, this.delegate.getName( ) );
final ManagedPolicyEntity newManagedPolicyEntity = new ManagedPolicyEntity( policyName );
newManagedPolicyEntity.setPath( path );
newManagedPolicyEntity.setDescription( description );
newManagedPolicyEntity.setText( policy );
newManagedPolicyEntity.setAccount( account );
final ManagedPolicyEntity persistedManagedPolicyEntity = Entities.persist( newManagedPolicyEntity );
final ManagedPolicyVersionEntity newManagedPolicyVersionEntity = new ManagedPolicyVersionEntity( newManagedPolicyEntity );
Entities.persist( newManagedPolicyVersionEntity );
newManagedPolicyEntity.applyDefaultPolicyVersion( newManagedPolicyVersionEntity );
db.commit( );
return new DatabaseManagedPolicyProxy( persistedManagedPolicyEntity );
} catch ( Exception e ) {
Debugging.logError( LOG, e, "Failed to add policy " + policy + " for " + this.delegate.getName( ) );
throw new AuthException( AuthException.POLICY_CREATE_FAILURE, e );
}
}
@Override
public void deletePolicy( final String policyName ) throws AuthException {
final String accountName = this.delegate.getName( );
if ( policyName == null ) {
throw new AuthException( AuthException.EMPTY_POLICY_NAME );
}
if ( policyHasResourceAttached( policyName, accountName ) ) {
throw new AuthException( AuthException.POLICY_DELETE_CONFLICT );
}
try ( final TransactionResource db = Entities.transactionFor( RoleEntity.class ) ) {
final ManagedPolicyEntity policy = DatabaseAuthUtils.getUniqueManagedPolicy( policyName, accountName );
Entities.delete( policy.getDefaultPolicyVersion( ) );
Entities.delete( policy );
db.commit( );
} catch ( NoSuchElementException e ) {
throw new AuthException( AuthException.NO_SUCH_POLICY, e );
} catch ( Exception e ) {
Debugging.logError( LOG, e, "Failed to delete policy: " + policyName + " in " + accountName );
throw new AuthException( AuthException.NO_SUCH_POLICY, 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 ( NoSuchElementException e ) {
throw new AuthException( AuthException.NO_SUCH_GROUP, e );
} 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 ( NoSuchElementException e ) {
throw new AuthException( AuthException.NO_SUCH_INSTANCE_PROFILE, e );
} 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 ( NoSuchElementException e ) {
throw new AuthException( AuthException.NO_SUCH_ROLE, e );
} catch ( Exception e ) {
Debugging.logError( LOG, e, "Failed to get role " + roleName + " for " + accountName );
throw new AuthException( AuthException.NO_SUCH_ROLE, e );
}
}
@Override
public EuareManagedPolicy lookupPolicyByName( final String policyName ) throws AuthException {
final String accountName = this.delegate.getName( );
if ( policyName == null ) {
throw new AuthException( AuthException.EMPTY_POLICY_NAME );
}
try ( final TransactionResource db = Entities.transactionFor( ManagedPolicyEntity.class ) ) {
final ManagedPolicyEntity policyEntity = DatabaseAuthUtils.getUniqueManagedPolicy( policyName, accountName );
return new DatabaseManagedPolicyProxy( policyEntity );
} catch ( NoSuchElementException e ) {
throw new AuthException( AuthException.NO_SUCH_POLICY, e );
} catch ( Exception e ) {
Debugging.logError( LOG, e, "Failed to get policy " + policyName + " for " + accountName );
throw new AuthException( AuthException.NO_SUCH_POLICY, 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 ( NoSuchElementException e ) {
throw new AuthException( AuthException.NO_SUCH_USER, e );
} 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 {
if(! ServerCertificateEntity.isCertificateNameValid(certName))
throw new AuthException(AuthException.INVALID_SERVER_CERT_NAME);
if(! ServerCertificateEntity.isCertificatePathValid(certPath))
throw new AuthException(AuthException.INVALID_SERVER_CERT_PATH);
final ServerCertificates.VerifiedCertInfo certInfo;
try{
certInfo = 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.setExpiration(certInfo.getExpiration());
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 {
try ( final TransactionResource db = Entities.transactionFor( ServerCertificateEntity.class ) ) {
final ServerCertificateEntity found = Entities.criteriaQuery(
ServerCertificateEntity.named( UserFullName.getInstance( this.lookupAdmin( ) ), certName )
).uniqueResult( );
Entities.delete( found );
db.commit();
return ServerCertificates.ToServerCertificate.INSTANCE.apply(found);
} catch(final NoSuchElementException ex){
throw new AuthException(AuthException.SERVER_CERT_NO_SUCH_ENTITY);
} catch(final Exception ex){
throw Exceptions.toUndeclared(ex);
}
}
@Override
public ServerCertificate lookupServerCertificate(final String certName) throws AuthException {
try ( final TransactionResource db = Entities.transactionFor( ServerCertificateEntity.class ) ) {
final ServerCertificateEntity serverCertificateEntity = Entities.criteriaQuery(
ServerCertificateEntity.named( UserFullName.getInstance( this.lookupAdmin( ) ), certName )
).readonly( ).uniqueResult( );
db.rollback();
return ServerCertificates.ToServerCertificateWithSecrets.INSTANCE.apply( serverCertificateEntity );
} 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(final String pathPrefix) throws AuthException {
final List<ServerCertificateEntity> result;
try ( final TransactionResource db = Entities.transactionFor( ServerCertificateEntity.class ) ) {
result = Entities.criteriaQuery(
ServerCertificateEntity.named( UserFullName.getInstance( this.lookupAdmin( ) ) )
).readonly( ).list( );
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;
final Iterable<ServerCertificateEntity> filtered;
if ( prefix.equals("/") ) {
filtered = result;
} else {
filtered = Iterables.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.newArrayList( Iterables.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 {
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;
}
}
@Override
public EuareOpenIdConnectProvider createOpenIdConnectProvider(String url, List<String> clientIDList, List<String> thumbprintList) throws AuthException {
Debugging.logError( LOG, null, "in Database layer: createOpenIdConnectProvider()");
final OIDCIssuerIdentifier issuerIdentifier;
final String issuerUrl;
try {
issuerIdentifier = OIDCUtils.parseIssuerIdentifier( url );
issuerUrl = issuerIdentifier.getHost( ) + issuerIdentifier.getPath( );
if ( issuerUrl.length() > 255 ) {
throw new AuthException( AuthException.INVALID_OPENID_PROVIDER_URL );
}
} catch ( final IllegalArgumentException e ) {
throw new AuthException( AuthException.INVALID_OPENID_PROVIDER_URL );
}
if ( thumbprintList==null || thumbprintList.isEmpty( ) ||
!thumbprintList.stream( ).allMatch( EuareOpenIdConnectProvider.THUMPRINT_PATTERN.asPredicate( ) )) {
throw new AuthException( AuthException.INVALID_OPENID_PROVIDER_THUMBPRINT );
}
if ( thumbprintList.size( ) > AuthenticationLimitProvider.Values.getOpenIdConnectProviderThumprintLimit( ) ) {
throw new AuthException( AuthException.QUOTA_EXCEEDED );
}
if ( clientIDList != null && !clientIDList.stream( ).allMatch( EuareOpenIdConnectProvider.CLIENT_ID_PATTERN.asPredicate( ) ) ) {
throw new AuthException( AuthException.INVALID_OPENID_PROVIDER_CLIENT_ID );
}
if ( clientIDList != null &&
clientIDList.size( ) > AuthenticationLimitProvider.Values.getOpenIdConnectProviderClientIdLimit( ) ) {
throw new AuthException( AuthException.QUOTA_EXCEEDED );
}
try {
lookupOpenIdConnectProvider( issuerUrl );
throw new AuthException(AuthException.OPENID_PROVIDER_ALREADY_EXISTS);
} catch( final AuthException ex ) {
if(!AuthException.NO_SUCH_OPENID_CONNECT_PROVIDER.equals(ex.getMessage())) {
throw ex;
}
}
try ( final TransactionResource db = Entities.transactionFor( AccountEntity.class ) ) {
final AccountEntity account =
DatabaseAuthUtils.getUnique( AccountEntity.class, AccountEntity_.name, this.delegate.getName( ) );
final OpenIdProviderEntity newOpenIdProvider = OpenIdProviderEntity.create(
account,
issuerIdentifier.getHost( ),
issuerIdentifier.getPort( ),
issuerIdentifier.getPath( ) );
newOpenIdProvider.getClientIDs().addAll( clientIDList );
newOpenIdProvider.getThumbprints().addAll( thumbprintList );
final OpenIdProviderEntity persistedOpenIdProvider = Entities.persist( newOpenIdProvider );
db.commit( );
return new DatabaseOpenIdProviderProxy( persistedOpenIdProvider );
} catch ( Exception e ) {
Debugging.logError( LOG, e, "Failed to add openid connect provider: " + url + " in " + this.delegate.getName() );
throw new AuthException( AuthException.OPENID_PROVIDER_CREATE_FAILURE, e );
}
}
public EuareOpenIdConnectProvider lookupOpenIdConnectProvider(final String url) throws AuthException {
final String accountName = this.delegate.getName( );
try ( final TransactionResource db = Entities.transactionFor( OpenIdProviderEntity.class ) ) {
final OpenIdProviderEntity openidproviderEntity = DatabaseAuthUtils.getUniqueOpenIdConnectProvider( url, accountName );
return new DatabaseOpenIdProviderProxy( openidproviderEntity );
} catch ( NoSuchElementException e ) {
throw new AuthException( AuthException.NO_SUCH_OPENID_CONNECT_PROVIDER, e );
} catch ( Exception e ) {
Debugging.logError( LOG, e, "Failed to get openid provider " + url + " for " + accountName );
throw new AuthException( AuthException.NO_SUCH_OPENID_CONNECT_PROVIDER, e );
}
}
@Override
public void deleteOpenIdConnectProvider(String url) throws AuthException {
final String accountName = this.delegate.getName( );
if (url == null ) {
throw new AuthException( AuthException.EMPTY_OPENID_PROVIDER_ARN );
}
try ( final TransactionResource db = Entities.transactionFor( OpenIdProviderEntity.class ) ) {
final OpenIdProviderEntity provider = DatabaseAuthUtils.getUniqueOpenIdConnectProvider( url, accountName );
Entities.delete( provider );
db.commit( );
} catch ( Exception e ) {
Debugging.logError( LOG, e, "Failed to delete openid connect provider: " + url + " in " + accountName );
throw new AuthException( AuthException.NO_SUCH_OPENID_CONNECT_PROVIDER, e );
}
}
@Override
public List<EuareOpenIdConnectProvider> listOpenIdConnectProviders() throws AuthException {
final List<EuareOpenIdConnectProvider> results = Lists.newArrayList( );
try ( final TransactionResource db = Entities.transactionFor( OpenIdProviderEntity.class ) ) {
List<OpenIdProviderEntity> providers = Entities
.criteriaQuery( OpenIdProviderEntity.class )
.join( OpenIdProviderEntity_.account ).whereEqual( AccountEntity_.name, this.delegate.getName( ) )
.list( );
for ( final OpenIdProviderEntity provider : providers ) {
results.add( new DatabaseOpenIdProviderProxy( provider ) );
}
return results;
} catch ( Exception e ) {
Debugging.logError( LOG, e, "Failed to get openid connect providers for " + this.delegate.getName( ) );
throw new AuthException( "Failed to get openid connect providers", e );
}
}
@Override
public EuareOpenIdConnectProvider getOpenIdConnectProvider(String url) throws AuthException {
final String accountName = this.delegate.getName( );
if (url == null ) {
throw new AuthException( AuthException.EMPTY_OPENID_PROVIDER_URL );
}
try ( final TransactionResource db = Entities.transactionFor( OpenIdProviderEntity.class ) ) {
final OpenIdProviderEntity provider = DatabaseAuthUtils.getUniqueOpenIdConnectProvider( url, accountName );
return new DatabaseOpenIdProviderProxy( provider );
} catch ( Exception e ) {
Debugging.logError( LOG, e, "Failed to delete openid connect provider: " + url + " in " + accountName );
throw new AuthException( AuthException.NO_SUCH_OPENID_CONNECT_PROVIDER, e );
}
}
@Override
public void addClientIdToOpenIdConnectProvider(String clientId, String url) throws AuthException {
final String accountName = this.delegate.getName( );
if (url == null ) {
throw new AuthException( AuthException.EMPTY_OPENID_PROVIDER_URL );
}
if ( clientId == null || !EuareOpenIdConnectProvider.CLIENT_ID_PATTERN.matcher( clientId ).matches( ) ) {
throw new AuthException( AuthException.INVALID_OPENID_PROVIDER_CLIENT_ID );
}
try ( final TransactionResource db = Entities.transactionFor( OpenIdProviderEntity.class ) ) {
final OpenIdProviderEntity provider = DatabaseAuthUtils.getUniqueOpenIdConnectProvider( url, accountName );
if ( !provider.getClientIDs( ).contains( clientId ) ) {
provider.getClientIDs().add( clientId );
}
if ( provider.getClientIDs().size( ) >
AuthenticationLimitProvider.Values.getOpenIdConnectProviderClientIdLimit( ) ) {
throw new AuthException( AuthException.QUOTA_EXCEEDED );
}
db.commit( );
return;
} catch ( Exception e ) {
Debugging.logError( LOG, e, "Failed to delete openid connect provider: " + url + " in " + accountName );
throw new AuthException( AuthException.NO_SUCH_OPENID_CONNECT_PROVIDER, e );
}
}
@Override
public void removeClientIdFromOpenIdConnectProvider(String clientId, String url) throws AuthException {
final String accountName = this.delegate.getName( );
if (url == null ) {
throw new AuthException( AuthException.EMPTY_OPENID_PROVIDER_URL );
}
try ( final TransactionResource db = Entities.transactionFor( OpenIdProviderEntity.class ) ) {
final OpenIdProviderEntity provider = DatabaseAuthUtils.getUniqueOpenIdConnectProvider( url, accountName );
provider.getClientIDs().remove(clientId);
db.commit( );
return;
} catch ( Exception e ) {
Debugging.logError( LOG, e, "Failed to delete openid connect provider: " + url + " in " + accountName );
throw new AuthException( AuthException.NO_SUCH_OPENID_CONNECT_PROVIDER, e );
}
}
@Override
public void updateOpenIdConnectProviderThumbprint(String url, List<String> thumbprintList) throws AuthException {
final String accountName = this.delegate.getName( );
if (url == null ) {
throw new AuthException( AuthException.EMPTY_OPENID_PROVIDER_URL );
}
if ( thumbprintList==null || thumbprintList.isEmpty( ) ||
!thumbprintList.stream( ).allMatch( EuareOpenIdConnectProvider.THUMPRINT_PATTERN.asPredicate( ) )) {
throw new AuthException( AuthException.INVALID_OPENID_PROVIDER_THUMBPRINT );
}
if ( thumbprintList.size( ) > AuthenticationLimitProvider.Values.getOpenIdConnectProviderThumprintLimit( ) ) {
throw new AuthException( AuthException.QUOTA_EXCEEDED );
}
try ( final TransactionResource db = Entities.transactionFor( OpenIdProviderEntity.class ) ) {
final OpenIdProviderEntity provider = DatabaseAuthUtils.getUniqueOpenIdConnectProvider( url, accountName );
provider.getThumbprints().clear();
provider.getThumbprints().addAll(thumbprintList);
db.commit( );
return;
} catch ( Exception e ) {
Debugging.logError( LOG, e, "Failed to update openid connect provider: " + url + " in " + accountName );
throw new AuthException( AuthException.NO_SUCH_OPENID_CONNECT_PROVIDER, e );
}
}
}