@Override
    public Credentials configure(final Host host) {
        final Credentials credentials = new Credentials(host.getCredentials());
        final String profile = credentials.getUsername();
        final Optional<Map.Entry<String, BasicProfile>> optional = profiles.entrySet().stream().filter(new Predicate<Map.Entry<String, BasicProfile>>() {
            @Override
            public boolean test(final Map.Entry<String, BasicProfile> entry) {
                final String profileName = entry.getKey();
                final BasicProfile basicProfile = entry.getValue();
                final String awsAccessIdKey = basicProfile.getAwsAccessIdKey();
                // Matching access key or profile name
                if(StringUtils.equals(profileName, profile)) {
                    if(log.isDebugEnabled()) {
                        log.debug(String.format("Found matching profile %s for profile name %s", profile, profileName));
                    }
                    return true;
                }
                else if(StringUtils.equals(awsAccessIdKey, profile)) {
                    if(log.isDebugEnabled()) {
                        log.debug(String.format("Found matching profile %s for access key %s", profile, awsAccessIdKey));
                    }
                    return true;
                }
                return false;
            }
        }).findFirst();
        if(optional.isPresent()) {
            final Map.Entry<String, BasicProfile> entry = optional.get();
            final BasicProfile basicProfile = entry.getValue();
            final String tokenCode;
            if(basicProfile.getProperties().containsKey("mfa_serial")) {
                try {
                    tokenCode = prompt.prompt(
                            host, LocaleFactory.localizedString("Provide additional login credentials", "Credentials"),
                            String.format("%s %s", LocaleFactory.localizedString("Multi-Factor Authentication", "S3"),
                                    basicProfile.getPropertyValue("mfa_serial")),
                            new LoginOptions(host.getProtocol())
                                    .password(true)
                                    .passwordPlaceholder(LocaleFactory.localizedString("MFA Authentication Code", "S3"))
                                    .keychain(false)
                    ).getPassword();
                }
                catch(LoginCanceledException e) {
                    log.warn(String.format("Canceled MFA prompt for profile %s", basicProfile));
                    return credentials;
                }
            }
            else {
                tokenCode = null;
            }
            final Integer durationSeconds;
            if(basicProfile.getProperties().containsKey("duration_seconds")) {
                durationSeconds = Integer.valueOf(basicProfile.getPropertyValue("duration_seconds"));
            }
            else {
                durationSeconds = null;
            }
            if(basicProfile.isRoleBasedProfile()) {
                if(log.isDebugEnabled()) {
                    log.debug(String.format("Configure credentials from role based profile %s", basicProfile.getProfileName()));
                }
                if(StringUtils.isBlank(basicProfile.getRoleSourceProfile())) {
                    log.warn(String.format("Missing source profile reference in profile %s", basicProfile.getProfileName()));
                    return credentials;
                }
                else if(!profiles.containsKey(basicProfile.getRoleSourceProfile())) {
                    log.warn(String.format("Missing source profile with name %s", basicProfile.getRoleSourceProfile()));
                    return credentials;
                }
                else {
                    final BasicProfile sourceProfile = profiles.get(basicProfile.getRoleSourceProfile());
                    final AWSSecurityTokenService service;
                    if(sourceProfile.getProperties().containsKey("sso_start_url")) {
                        // Read cached SSO credentials
                        final CachedCredential cached = this.fetchSsoCredentials(sourceProfile.getProperties());
                        if(null == cached) {
                            return credentials;
                        }
                        service = this.getTokenService(host, host.getRegion(),
                                cached.accessKey, cached.secretKey, cached.sessionToken);
                    }
                    else {
                        // If a profile defines the role_arn property then the profile is treated as an assume role profile
                        service = this.getTokenService(host, host.getRegion(),
                                sourceProfile.getAwsAccessIdKey(),
                                sourceProfile.getAwsSecretAccessKey(),
                                sourceProfile.getAwsSessionToken());
                    }
                    // Starts a new session by sending a request to the AWS Security Token Service (STS) to assume a
                    // role using the long-lived AWS credentials
                    final AssumeRoleRequest assumeRoleRequest = new AssumeRoleRequest()
                            .withExternalId(basicProfile.getRoleExternalId())
                            .withRoleArn(basicProfile.getRoleArn())
                            // Specify this value if the IAM user has a policy that requires MFA authentication
                            .withSerialNumber(basicProfile.getPropertyValue("mfa_serial"))
                            // The value provided by the MFA device, if MFA is required
                            .withTokenCode(tokenCode
                                    // mfa_serial - The identification number of the MFA device to use when assuming a role. This is an optional parameter.
                                    // Specify this value if the trust policy of the role being assumed includes a condition that requires MFA authentication.
                                    // The value is either the serial number for a hardware device (such as GAHT12345678) or an Amazon Resource Name (ARN) for
                                    // a virtual device (such as arn:aws:iam::123456789012:mfa/user).
                            )
                            .withRoleSessionName(basicProfile.getRoleSessionName() == null ? new AsciiRandomStringService().random() : basicProfile.getRoleSessionName())
                            .withDurationSeconds(durationSeconds
                                    // duration_seconds - Specifies the maximum duration of the role session, in seconds. The value can range from 900 seconds
                                    // (15 minutes) up to the maximum session duration setting for the role (which can be a maximum of 43200). This is an
                                    // optional parameter and by default, the value is set to 3600 seconds.
                            );
                    if(log.isDebugEnabled()) {
                        log.debug(String.format("Request %s from %s", assumeRoleRequest, service));
                    }
                    try {
                        final AssumeRoleResult assumeRoleResult = service.assumeRole(assumeRoleRequest);
                        if(log.isDebugEnabled()) {
                            log.debug(String.format("Set credentials from %s", assumeRoleResult));
                        }
                        credentials.setTokens(new TemporaryAccessTokens(
                                assumeRoleResult.getCredentials().getAccessKeyId(),
                                assumeRoleResult.getCredentials().getSecretAccessKey(),
                                assumeRoleResult.getCredentials().getSessionToken(),
                                assumeRoleResult.getCredentials().getExpiration().getTime()));
                    }
                    catch(AWSSecurityTokenServiceException e) {
                        log.warn(e.getErrorMessage(), e);
                        return credentials;
                    }
                }
            }
            else {
                if(log.isDebugEnabled()) {
                    log.debug(String.format("Configure credentials from basic profile %s", basicProfile.getProfileName()));
                }
                final Map<String, String> profileProperties = basicProfile.getProperties();
                if(profileProperties.containsKey("sso_start_url") || profileProperties.containsKey("sso_session")) {
                    // Read cached SSO credentials
                    final CachedCredential cached = this.fetchSsoCredentials(profileProperties);
                    if(null == cached) {
                        return credentials;
                    }
                    return credentials.withTokens(new TemporaryAccessTokens(
                            cached.accessKey, cached.secretKey, cached.sessionToken,
                            Instant.parse(cached.expiration).toEpochMilli()));
                }
                if(tokenCode != null) {
                    // Obtain session token
                    if(log.isDebugEnabled()) {
                        log.debug(String.format("Get session token from credentials in profile %s", basicProfile.getProfileName()));
                    }
                    final AWSSecurityTokenService service = this.getTokenService(host,
                            host.getRegion(),
                            basicProfile.getAwsAccessIdKey(),
                            basicProfile.getAwsSecretAccessKey(),
                            basicProfile.getAwsSessionToken());
                    //  The purpose of the sts:GetSessionToken operation is to authenticate the user using MFA.
                    final GetSessionTokenRequest sessionTokenRequest = new GetSessionTokenRequest()
                            // The value provided by the MFA device, if MFA is required
                            .withTokenCode(tokenCode)
                            // Specify this value if the IAM user has a policy that requires MFA authentication
                            .withSerialNumber(basicProfile.getPropertyValue("mfa_serial"))
                            .withDurationSeconds(durationSeconds);
                    if(log.isDebugEnabled()) {
                        log.debug(String.format("Request %s from %s", sessionTokenRequest, service));
                    }
                    try {
                        final GetSessionTokenResult sessionTokenResult = service.getSessionToken(sessionTokenRequest);
                        if(log.isDebugEnabled()) {
                            log.debug(String.format("Set credentials from %s", sessionTokenResult));
                        }
                        return credentials.withTokens(new TemporaryAccessTokens(
                                sessionTokenResult.getCredentials().getAccessKeyId(),
                                sessionTokenResult.getCredentials().getSecretAccessKey(),
                                sessionTokenResult.getCredentials().getSessionToken(),
                                sessionTokenResult.getCredentials().getExpiration().getTime()));
                    }
                    catch(AWSSecurityTokenServiceException e) {
                        log.warn(e.getErrorMessage(), e);
                        return credentials;
                    }
                }
                if(log.isDebugEnabled()) {
                    log.debug(String.format("Set credentials from profile %s", basicProfile.getProfileName()));
                }
                return credentials
                        .withTokens(new TemporaryAccessTokens(
                                basicProfile.getAwsAccessIdKey(),
                                basicProfile.getAwsSecretAccessKey(),
                                basicProfile.getAwsSessionToken(),
                                -1L))
                        .withUsername(basicProfile.getAwsAccessIdKey())
                        .withPassword(basicProfile.getAwsSecretAccessKey());
            }
        }
        else {
            log.warn(String.format("No matching configuration for profile %s in %s", profile, profiles));
        }
        return credentials;
    }
@Test
    public void testConfigure() throws Exception {
        new S3CredentialsConfigurator(new DisabledX509TrustManager(), new DefaultX509KeyManager(), new DisabledPasswordCallback())
                .reload().configure(new Host(new TestProtocol()));
    }