/*************************************************************************
* Copyright 2009-2015 Eucalyptus Systems, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*
* Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta
* CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need
* additional information or have any questions.
************************************************************************/
package com.eucalyptus.auth.tokens;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.BasicSessionCredentials;
import com.eucalyptus.auth.Accounts;
import com.eucalyptus.auth.AuthException;
import com.eucalyptus.auth.principal.AccountFullName;
import com.eucalyptus.auth.principal.HasRole;
import com.eucalyptus.auth.principal.Role;
import com.eucalyptus.auth.principal.User;
import com.eucalyptus.util.Exceptions;
import com.eucalyptus.util.Pair;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
/**
*
*/
@SuppressWarnings( { "Guava", "WeakerAccess" } )
public class SecurityTokenAWSCredentialsProvider implements AWSCredentialsProvider {
private static final int DEFAULT_EXPIRATION_SECS = 900;
private static final int DEFAULT_PRE_EXPIRY_SECS = 60;
private final AtomicReference<Supplier<AWSCredentials>> credentialsSupplier = new AtomicReference<>( );
private final Supplier<User> user;
private final Supplier<Pair<Role,RoleSecurityTokenAttributes>> role;
private final int expirationSecs;
private final int preExpirySecs;
public static SecurityTokenAWSCredentialsProvider forUserOrRole( final User user ) {
if ( user instanceof HasRole && ((HasRole) user).getRole( ) != null ) {
final Role role = ((HasRole) user).getRole( );
final RoleSecurityTokenAttributes attributes =
RoleSecurityTokenAttributes.forUser( user )
.or( RoleSecurityTokenAttributes.basic( "eucalyptus" ) );
return new SecurityTokenAWSCredentialsProvider( role, attributes );
} else {
return new SecurityTokenAWSCredentialsProvider( user );
}
}
public SecurityTokenAWSCredentialsProvider( final AccountFullName accountFullName ) {
this( () -> {
try {
return Accounts.lookupPrincipalByAccountNumber( accountFullName.getAccountNumber( ) );
} catch ( AuthException e ) {
throw Exceptions.toUndeclared( e );
}
} );
}
public SecurityTokenAWSCredentialsProvider( final User user ) {
this( Suppliers.ofInstance( user ) );
}
public SecurityTokenAWSCredentialsProvider( final Supplier<User> user ) {
this( user, DEFAULT_EXPIRATION_SECS );
}
public SecurityTokenAWSCredentialsProvider( final Supplier<User> user, final int expirationSecs ) {
this( user, Math.max( expirationSecs, DEFAULT_PRE_EXPIRY_SECS * 2 ), DEFAULT_PRE_EXPIRY_SECS );
}
public SecurityTokenAWSCredentialsProvider( final User user, final int expirationSecs, final int preExpirySecs ) {
this( Suppliers.ofInstance( user ), expirationSecs, preExpirySecs );
}
public SecurityTokenAWSCredentialsProvider( final Supplier<User> user, final int expirationSecs, final int preExpirySecs ) {
this( user, null, expirationSecs, preExpirySecs );
}
public SecurityTokenAWSCredentialsProvider( final Role role, final RoleSecurityTokenAttributes attributes ) {
this( null, Suppliers.ofInstance( Pair.pair( role, attributes ) ), DEFAULT_EXPIRATION_SECS, DEFAULT_PRE_EXPIRY_SECS );
}
private SecurityTokenAWSCredentialsProvider(
final Supplier<User> user,
final Supplier<Pair<Role,RoleSecurityTokenAttributes>> role,
final int expirationSecs,
final int preExpirySecs
) {
this.user = user;
this.role = role;
this.expirationSecs = Math.max( expirationSecs, DEFAULT_PRE_EXPIRY_SECS * 2 );
this.preExpirySecs = preExpirySecs;
refresh( );
}
@Override
public AWSCredentials getCredentials( ) {
return credentialsSupplier.get( ).get( );
}
@Override
public void refresh( ) {
credentialsSupplier.set( refreshCredentialsSupplier( ) );
}
private Supplier<AWSCredentials> refreshCredentialsSupplier( ) {
return Suppliers.memoizeWithExpiration( () -> {
try {
final SecurityToken securityToken = user != null ?
SecurityTokenManager.issueSecurityToken( user.get( ), expirationSecs ) :
SecurityTokenManager.issueSecurityToken( role.get( ).getLeft( ), role.get( ).getRight( ), expirationSecs );
return new BasicSessionCredentials(
securityToken.getAccessKeyId( ),
securityToken.getSecretKey( ),
securityToken.getToken( ) );
} catch ( final AuthException e ) {
throw Exceptions.toUndeclared( e );
}
}, expirationSecs - preExpirySecs, TimeUnit.SECONDS );
}
}