/*************************************************************************
* 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.
************************************************************************/
package com.eucalyptus.auth.euare;
import static com.eucalyptus.auth.principal.Certificate.Util.active;
import static com.eucalyptus.util.CollectionUtils.propertyPredicate;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.eucalyptus.auth.AccessKeys;
import com.eucalyptus.auth.AuthException;
import com.eucalyptus.auth.euare.common.policy.IamPolicySpec;
import com.eucalyptus.auth.euare.persist.DatabaseAuthUtils;
import com.eucalyptus.auth.euare.persist.DatabaseManagedPolicyProxy;
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.GroupEntity;
import com.eucalyptus.auth.euare.persist.entities.ManagedPolicyEntity;
import com.eucalyptus.auth.euare.persist.entities.PolicyEntity;
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.EuareRole;
import com.eucalyptus.auth.euare.principal.EuareUser;
import com.eucalyptus.auth.policy.ern.EuareResourceName;
import com.eucalyptus.auth.principal.AccessKey;
import com.eucalyptus.auth.principal.BaseRole;
import com.eucalyptus.auth.principal.Certificate;
import com.eucalyptus.auth.principal.HasRole;
import com.eucalyptus.auth.principal.OwnerFullName;
import com.eucalyptus.auth.principal.Policy;
import com.eucalyptus.auth.principal.PolicyScope;
import com.eucalyptus.auth.principal.PolicyVersion;
import com.eucalyptus.auth.principal.PolicyVersions;
import com.eucalyptus.auth.principal.Role;
import com.eucalyptus.auth.principal.User;
import com.eucalyptus.auth.principal.UserPrincipal;
import com.eucalyptus.auth.util.X509CertHelper;
import com.eucalyptus.crypto.Digest;
import com.eucalyptus.util.NonNullFunction;
import com.eucalyptus.util.Strings;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Objects;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.io.BaseEncoding;
/**
*
*/
public class UserPrincipalImpl implements UserPrincipal, HasRole {
private static final long serialVersionUID = 1L;
@Nonnull
private final String name;
@Nonnull
private final String path;
@Nonnull
private final String userId;
@Nonnull
private final String authenticatedId;
@Nullable
private final String token;
@Nonnull
private final String accountAlias;
@Nonnull
private final String accountNumber;
@Nonnull
private final String canonicalId;
private final boolean enabled;
private final boolean accountAdmin;
private final boolean systemAdmin;
private final boolean systemUser;
@Nullable
private final String password;
@Nullable
private final Long passwordExpires;
@Nullable
private final Role role;
@Nonnull
private final ImmutableList<AccessKey> keys;
@Nonnull
private final ImmutableList<Certificate> certificates;
@Nonnull
private final ImmutableList<PolicyVersion> principalPolicies;
/**
* TODO - When changing fields, update ptag calculation
* TODO - When changing fields, update ptag calculation
* TODO - When changing fields, update ptag calculation
* TODO - When changing fields, update ptag calculation
* TODO - When changing fields, update ptag calculation
* @see #ptag(UserPrincipal)
*/
@Nullable
private final String ptag;
public UserPrincipalImpl( final UserEntity user ) throws AuthException {
final List<GroupEntity> groups = user.getGroups();
final AccountEntity account = groups.get( 0 ).getAccount( );
final List<PolicyVersion> policies = Lists.newArrayList( );
if ( user.isEnabled( ) ) {
if ( DatabaseAuthUtils.isAccountAdmin( user.getName( ) ) ) {
policies.add( PolicyVersions.getAdministratorPolicy( ) );
} else {
for ( final GroupEntity group : groups ) {
if ( group.isUserGroup( ) ) {
Iterables.addAll(
policies,
Iterables.transform(
group.getPolicies( ),
Functions.compose( PolicyVersions.policyVersion( PolicyScope.User, new EuareResourceName( account.getAccountNumber( ), IamPolicySpec.IAM_RESOURCE_USER, user.getPath( ), user.getName( ) ).toString( ) ), PolicyTransform.INSTANCE ) ) );
}
}
for ( final ManagedPolicyEntity managedPolicy : user.getAttachedPolicies( ) ) {
final EuareManagedPolicy euareManagedPolicy = new DatabaseManagedPolicyProxy( managedPolicy );
policies.add( PolicyVersions.policyVersion( euareManagedPolicy, Accounts.getManagedPolicyArn( euareManagedPolicy ) ) );
}
for ( final GroupEntity group : groups ) {
if ( !group.isUserGroup( ) ) {
Iterables.addAll(
policies,
Iterables.transform(
group.getPolicies( ),
Functions.compose( PolicyVersions.policyVersion( PolicyScope.Group, new EuareResourceName( account.getAccountNumber( ), IamPolicySpec.IAM_RESOURCE_GROUP, group.getPath( ), group.getName( ) ).toString( ) ), PolicyTransform.INSTANCE ) ) );
for ( final ManagedPolicyEntity managedPolicy : group.getAttachedPolicies( ) ) {
final EuareManagedPolicy euareManagedPolicy = new DatabaseManagedPolicyProxy( managedPolicy );
policies.add( PolicyVersions.policyVersion( euareManagedPolicy, Accounts.getManagedPolicyArn( euareManagedPolicy ) ) );
}
}
}
}
UserEntity admin;
try {
admin = DatabaseAuthUtils.getUniqueUser( User.ACCOUNT_ADMIN, account.getName( ) );
} catch ( Exception e ) {
throw new AuthException( e );
}
if ( admin != null ) {
for ( final GroupEntity group : admin.getGroups( ) ) {
if ( group.isUserGroup( ) ) {
Iterables.addAll(
policies,
Iterables.transform(
group.getPolicies( ),
Functions.compose( PolicyVersions.policyVersion( PolicyScope.Account, account.getAccountNumber( ) ), PolicyTransform.INSTANCE ) ) );
}
}
}
}
this.name = user.getName( );
this.path = user.getPath();
this.userId = user.getUserId();
this.authenticatedId = user.getUserId();
this.canonicalId = account.getCanonicalId();
this.token = user.getToken();
this.accountAlias = account.getName();
this.accountNumber = account.getAccountNumber();
this.enabled = user.isEnabled();
this.accountAdmin = DatabaseAuthUtils.isAccountAdmin( user.getName( ) );
this.systemAdmin = Accounts.isAdministrativeAccount( account.getName( ) );
this.systemUser = systemAdmin;
this.password = user.getPassword();
this.passwordExpires = password == null ? null : Objects.firstNonNull( user.getPasswordExpires( ), Long.MAX_VALUE );
this.role = null;
this.keys = ImmutableList.copyOf( Iterables.filter( Iterables.transform( user.getKeys( ), ekeyWrapper( this ) ), AccessKeys.isActive( ) ) );
this.certificates = ImmutableList.copyOf(
Iterables.filter( Iterables.transform( user.getCertificates( ), ecertWrapper( this ) ), propertyPredicate( true, active( ) ) ) );
this.principalPolicies = ImmutableList.copyOf( policies );
this.ptag = null;
}
public UserPrincipalImpl( final EuareUser user ) throws AuthException {
final EuareAccount account = user.getAccount();
final List<PolicyVersion> policies = Lists.newArrayList( );
if ( user.isEnabled( ) ) {
if ( user.isAccountAdmin() ) {
policies.add( PolicyVersions.getAdministratorPolicy() );
} else {
Iterables.addAll(
policies,
Iterables.transform(
user.getPolicies( ),
PolicyVersions.policyVersion( PolicyScope.User, Accounts.getUserArn( user ) ) ) );
for ( final EuareManagedPolicy managedPolicy : user.getAttachedPolicies( ) ) {
policies.add( PolicyVersions.policyVersion( managedPolicy, Accounts.getManagedPolicyArn( managedPolicy ) ) );
}
for ( final EuareGroup group : Iterables.filter( user.getGroups(), Predicates.not( Accounts.isUserGroup() ) ) ) {
Iterables.addAll(
policies,
Iterables.transform(
group.getPolicies( ),
PolicyVersions.policyVersion( PolicyScope.Group, Accounts.getGroupArn( group ) ) ) );
for ( final EuareManagedPolicy managedPolicy : group.getAttachedPolicies( ) ) {
policies.add( PolicyVersions.policyVersion( managedPolicy, Accounts.getManagedPolicyArn( managedPolicy ) ) );
}
}
}
EuareUser admin;
try {
admin = account.lookupAdmin();
} catch ( AuthException e ) {
throw new AuthException( e );
}
if ( admin != null ) {
Iterables.addAll(
policies,
Iterables.transform(
admin.getPolicies(),
PolicyVersions.policyVersion( PolicyScope.Account, user.getAccountNumber() ) ) ) ;
}
}
this.name = user.getName( );
this.path = user.getPath();
this.userId = user.getUserId();
this.authenticatedId = user.getUserId();
this.canonicalId = account.getCanonicalId();
this.token = user.getToken();
this.accountAlias = account.getName();
this.accountNumber = account.getAccountNumber();
this.enabled = user.isEnabled();
this.accountAdmin = user.isAccountAdmin();
this.systemAdmin = user.isSystemAdmin();
this.systemUser = user.isSystemUser();
this.password = user.getPassword();
this.passwordExpires = password == null ? null : Objects.firstNonNull( user.getPasswordExpires( ), Long.MAX_VALUE );
this.role = null;
this.keys = ImmutableList.copyOf( Iterables.filter( Iterables.transform( user.getKeys( ), keyWrapper( this ) ), AccessKeys.isActive( ) ) );
this.certificates = ImmutableList.copyOf(
Iterables.filter( user.getCertificates( ), propertyPredicate( true, active( ) ) ) );
this.principalPolicies = ImmutableList.copyOf( policies );
this.ptag = null;
}
public UserPrincipalImpl( final EuareRole role, final String sessionName ) throws AuthException {
final EuareAccount account = role.getAccount( );
final EuareUser user = account.lookupAdmin();
final List<PolicyVersion> policies = Lists.newArrayList( );
Iterables.addAll(
policies,
Iterables.transform(
role.getPolicies( ),
PolicyVersions.policyVersion( PolicyScope.Role, Accounts.getRoleArn( role ) ) ) );
for ( final EuareManagedPolicy managedPolicy : role.getAttachedPolicies( ) ) {
policies.add( PolicyVersions.policyVersion( managedPolicy, Accounts.getManagedPolicyArn( managedPolicy ) ) );
}
Iterables.addAll(
policies,
Iterables.transform(
user.getPolicies(),
PolicyVersions.policyVersion( PolicyScope.Account, user.getAccountNumber( ) ) ) );
this.name = user.getName( );
this.path = user.getPath();
this.userId = user.getUserId();
this.authenticatedId = role.getRoleId() + ( sessionName == null ? "" : ":" + sessionName );
this.canonicalId = account.getCanonicalId();
this.token = null;
this.accountAlias = account.getName( );
this.accountNumber = account.getAccountNumber();
this.enabled = true;
this.accountAdmin = false;
this.systemAdmin = false;
this.systemUser = user.isSystemUser( );
this.password = null;
this.passwordExpires = null;
this.role = immutableRole( role );
this.keys = ImmutableList.copyOf( Collections.<AccessKey>emptyIterator( ) );
this.certificates = ImmutableList.copyOf( Collections.<Certificate>emptyIterator() );
this.principalPolicies = ImmutableList.copyOf( policies );
this.ptag = null;
}
public UserPrincipalImpl(
final UserPrincipal principal,
final Iterable<AccessKey> keys
) throws AuthException {
this.name = principal.getName( );
this.path = principal.getPath();
this.userId = principal.getUserId();
this.authenticatedId = principal.getAuthenticatedId();
this.canonicalId = principal.getCanonicalId();
this.token = principal.getToken();
this.accountAlias = principal.getAccountAlias();
this.accountNumber = principal.getAccountNumber();
this.enabled = principal.isEnabled();
this.accountAdmin = principal.isAccountAdmin( );
this.systemAdmin = principal.isSystemAdmin( );
this.systemUser = principal.isSystemUser( );
this.password = null;
this.passwordExpires = null;
this.role = principal instanceof HasRole ? ((HasRole) principal).getRole( ) : null;
this.keys = ImmutableList.copyOf( keys );
this.certificates = ImmutableList.copyOf( principal.getCertificates() );
this.principalPolicies = ImmutableList.copyOf( principal.getPrincipalPolicies() );
this.ptag = null;
}
@Nonnull
public String getName( ) {
return name;
}
@Nonnull
public String getPath( ) {
return path;
}
@Nonnull
public String getUserId( ) {
return userId;
}
@Nonnull
public String getAuthenticatedId( ) {
return authenticatedId;
}
@Nullable
public String getToken( ) {
return token;
}
@Nonnull
public String getAccountAlias( ) {
return accountAlias;
}
@Nonnull
public String getAccountNumber( ) {
return accountNumber;
}
@Nonnull
public String getCanonicalId( ) {
return canonicalId;
}
public boolean isEnabled( ) {
return enabled;
}
@Override
public boolean isAccountAdmin() {
return accountAdmin;
}
@Override
public boolean isSystemAdmin( ) {
return systemAdmin;
}
@Override
public boolean isSystemUser( ) {
return systemUser;
}
@Override
@Nullable
public String getPassword( ) {
return password;
}
@Override
@Nullable
public Long getPasswordExpires( ) {
return passwordExpires;
}
@Nullable
public Role getRole( ) {
return role;
}
@Nonnull
public ImmutableList<AccessKey> getKeys( ) {
return keys;
}
@Nonnull
public ImmutableList<Certificate> getCertificates( ) {
return certificates;
}
@Nonnull
public ImmutableList<PolicyVersion> getPrincipalPolicies( ) {
return principalPolicies;
}
@Nullable
public String getPTag( ) {
return ptag;
}
/**
* Calculate the tag for the given principal.
*/
public static String ptag( final UserPrincipal userPrincipal ) {
final List<CharSequence> sequences = Lists.newArrayList( );
sequences.add( userPrincipal.getAccountAlias( ) );
sequences.add( userPrincipal.getAccountNumber( ) );
sequences.add( userPrincipal.getAuthenticatedId( ) );
sequences.add( userPrincipal.getCanonicalId( ) );
sequences.add( userPrincipal.getName( ) );
sequences.add( String.valueOf( userPrincipal.getToken( ) ) );
sequences.add( String.valueOf( userPrincipal.getPassword( ) ) );
sequences.add( String.valueOf( userPrincipal.getPasswordExpires( ) ) );
sequences.add( userPrincipal.getPath( ) );
sequences.add( userPrincipal.getUserId( ) );
sequences.add( String.valueOf( userPrincipal.isAccountAdmin( ) ) );
sequences.add( String.valueOf( userPrincipal.isEnabled( ) ) );
sequences.add( String.valueOf( userPrincipal.isSystemAdmin( ) ) );
sequences.add( String.valueOf( userPrincipal.isSystemUser( ) ) );
for ( final AccessKey key : userPrincipal.getKeys( ) ) {
sequences.add( String.valueOf( key.getAccessKey( ) ) );
sequences.add( String.valueOf( key.isActive( ) ) );
}
for ( final Certificate certificate : userPrincipal.getCertificates( ) ) {
sequences.add( certificate.getCertificateId( ) );
sequences.add( String.valueOf( certificate.isActive( ) ) );
}
for ( final PolicyVersion policyVersion : userPrincipal.getPrincipalPolicies( ) ) {
sequences.add( policyVersion.getPolicyVersionId( ) );
sequences.add( policyVersion.getPolicyHash( ) );
}
return BaseEncoding.base64( ).encode( Digest.SHA256.digestBinary( StandardCharsets.UTF_8.encode( CharBuffer.wrap( Strings.concat(
sequences
) ) ) ) );
}
private static Role immutableRole( final BaseRole role ) throws AuthException {
final String accountNumber = role.getAccountNumber( );
final String roleArn = role.getRoleArn( );
final String roleId = role.getRoleId( );
final String path = role.getPath( );
final String name = role.getName( );
final String secret = role.getSecret( );
final String displayName = role.getDisplayName( );
final OwnerFullName owner = role.getOwner( );
final PolicyVersion policyVersion = role.getPolicy( );
return new Role( ) {
@Override public String getAccountNumber( ) { return accountNumber; }
@Override public String getRoleArn( ) { return roleArn; }
@Override public String getRoleId( ) { return roleId; }
@Override public String getPath( ) { return path; }
@Override public String getName( ) { return name; }
@Override public String getSecret( ) { return secret; }
@Override public String getDisplayName( ) { return displayName; }
@Override public OwnerFullName getOwner( ) { return owner; }
@Override public PolicyVersion getPolicy( ) { return policyVersion; }
};
}
private static NonNullFunction<AccessKey,AccessKey> keyWrapper( final UserPrincipal userPrincipal ) {
return new NonNullFunction<AccessKey, AccessKey>() {
@Nonnull
@Override
public AccessKey apply( final AccessKey accessKey ) {
return new AccessKey( ){
@Override public Boolean isActive( ) { return accessKey.isActive( ); }
@Override public String getAccessKey() { return accessKey.getAccessKey( ); }
@Override public String getSecretKey( ) { return accessKey.getSecretKey( ); }
@Override public Date getCreateDate( ) { return accessKey.getCreateDate( ); }
@Override public UserPrincipal getPrincipal( ) { return userPrincipal; }
};
}
};
}
private static NonNullFunction<AccessKeyEntity,AccessKey> ekeyWrapper( final UserPrincipal userPrincipal ) {
return new NonNullFunction<AccessKeyEntity, AccessKey>() {
@Nonnull
@Override
public AccessKey apply( final AccessKeyEntity accessKey ) {
return new AccessKey( ){
@Override public Boolean isActive( ) { return accessKey.isActive( ); }
@Override public String getAccessKey() { return accessKey.getAccessKey( ); }
@Override public String getSecretKey( ) { return accessKey.getSecretKey( ); }
@Override public Date getCreateDate( ) { return accessKey.getCreateDate( ); }
@Override public UserPrincipal getPrincipal( ) { return userPrincipal; }
};
}
};
}
private static NonNullFunction<CertificateEntity,Certificate> ecertWrapper( final UserPrincipal userPrincipal ) {
return new NonNullFunction<CertificateEntity, Certificate>( ) {
@Nonnull
@Override
public Certificate apply( final CertificateEntity accessKey ) {
return new Certificate( ){
@Override public String getCertificateId( ) { return accessKey.getCertificateId( ); }
@Override public Boolean isActive( ) { return accessKey.isActive(); }
@Override public String getPem( ) { return accessKey.getPem( ); }
@Override public X509Certificate getX509Certificate( ) { return X509CertHelper.toCertificate( getPem() ); }
@Override public Date getCreateDate( ) { return accessKey.getCreateDate( ); }
@Override public UserPrincipal getPrincipal( ) { return userPrincipal; }
};
}
};
}
private enum PolicyTransform implements Function<PolicyEntity,Policy> {
INSTANCE {
@Override
public Policy apply( final PolicyEntity policyEntity ) {
return new Policy( ) {
@Override
public String getName() {
return policyEntity.getName( );
}
@Override
public String getText() {
return policyEntity.getText( );
}
@Override
public Integer getPolicyVersion() {
return policyEntity.getVersion( );
}
};
}
}
}
}