class ZTSImpl implements KeyStore, ZTSHandler {

    public AWSTemporaryCredentials getAWSTemporaryCredentials(ResourceContext ctx, String domainName,
            String roleName, Integer durationSeconds, String externalId) {

        final String caller = ctx.getApiName();

        // we need to make sure we don't log the external id in
        // our access log files so we're going to set the attribute
        // to skip the query parameters

        ctx.request().setAttribute(ZTS_REQUEST_LOG_SKIP_QUERY, Boolean.TRUE);

        final String principalDomain = logPrincipalAndGetDomain(ctx);
        validateRequest(ctx.request(), principalDomain, caller);
        validate(domainName, TYPE_DOMAIN_NAME, principalDomain, caller);

        // verify that this is not an authorized service principal
        // which is only supported for get role token operations

        final Principal principal = ((RsrcCtxWrapper) ctx).principal();

        if (isAuthorizedServicePrincipal(principal)) {
            throw forbiddenError("Authorized Service Principals not allowed",
                    caller, domainName, principalDomain);
        }

        // validate principal object to make sure we're not
        // processing a role identity and instead we require
        // a service identity

        validatePrincipalNotRoleIdentity(principal, caller);

        // since the role name might contain a path and thus it has
        // been encoded, we're going to decode it first before using it
        
        try {
            roleName = URLDecoder.decode(roleName, "UTF-8");
        } catch (Exception ex) {
            LOGGER.error("Unable to decode {} - error {}", roleName, ex.getMessage());
        }
        validate(roleName, TYPE_AWS_ARN_ROLE_NAME, principalDomain, caller);
        
        // for consistent handling of all requests, we're going to convert
        // all incoming object values into lower case since ZMS Server
        // saves all of its object names in lower case. However, since
        // for roleName we need to pass that to AWS, we're not going to
        // convert here instead only for the authz check
        
        domainName = domainName.toLowerCase();
        setRequestDomain(ctx, domainName);

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("getAWSTemporaryCredentials(domain: {}, role: {}, duration {}",
                    domainName, roleName, durationSeconds);
        }
        
        if (!cloudStore.isAwsEnabled()) {
            throw requestError("getAWSTemporaryCredentials: AWS support is not available",
                    caller, domainName, principalDomain);
        }
        
        // get our principal's name
        
        final String principalName = principal.getFullName();
        final String roleResource = domainName + ":" + roleName.toLowerCase();

        // we need to first verify that our principal is indeed configured
        // with aws assume role assertion for the specified role and domain
        
        if (!verifyAWSAssumeRole(domainName, roleResource, principalName)) {
            throw forbiddenError("getAWSTemporaryCredentials: Forbidden (ASSUME_AWS_ROLE on "
                    + roleResource + " for " + principalName + ")", caller, domainName, principalDomain);
        }
        
        // now need to get the associated cloud account for the domain name
        
        String account = cloudStore.getCloudAccount(domainName);
        if (account == null) {
            throw requestError("getAWSTemporaryCredentials: unable to retrieve AWS account for: "
                    + domainName, caller, domainName, principalDomain);
        }
        
        // obtain the credentials from the cloud store
        
        AWSTemporaryCredentials creds = cloudStore.assumeAWSRole(account, roleName, principalName,
                durationSeconds, externalId);
        if (creds == null) {
            throw requestError("getAWSTemporaryCredentials: unable to assume role " + roleName
                    + " in domain " + domainName + " for principal " + principalName,
                    caller, domainName, principalDomain);
        }
        
        return creds;
    }

    public  ZTSImpl();
    public  ZTSImpl(CloudStore implCloudStore, DataStore implDataStore);

}