class ZTSImpl implements KeyStore, ZTSHandler {

    @Deprecated
    @Override
    public Identity postInstanceRefreshRequest(ResourceContext ctx, String domain,
            String service, InstanceRefreshRequest req) {

        final String caller = ctx.getApiName();
        final String principalDomain = logPrincipalAndGetDomain(ctx);

        if (readOnlyMode) {
            throw requestError("Server in Maintenance Read-Only mode. Please try your request later",
                    caller, ZTSConsts.ZTS_UNKNOWN_DOMAIN, principalDomain);
        }
        
        validateRequest(ctx.request(), principalDomain, caller);
        validate(domain, TYPE_DOMAIN_NAME, principalDomain, caller);
        validate(service, TYPE_SIMPLE_NAME, principalDomain, caller);
        validate(req, TYPE_INSTANCE_REFRESH_REQUEST, principalDomain, caller);

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

        final Principal principal = ((RsrcCtxWrapper) ctx).principal();
        validatePrincipalNotRoleIdentity(principal, caller);

        // for consistent handling of all requests, we're going to convert
        // all incoming object values into lower case (e.g. domain, role,
        // policy, service, etc name)
        
        domain = domain.toLowerCase();
        setRequestDomain(ctx, domain);
        service = service.toLowerCase();

        // make sure the credentials match to whatever the request is

        String fullServiceName = domain + "." + service;
        final String principalName = principal.getFullName();
        boolean userRequest = false;

        if (!fullServiceName.equals(principalName)) {
            
            // if this not a match then we're going to allow the operation
            // only if the principal has been authorized to manage
            // services within the given domain
            
            try {
                userRequest = authorizer.access("update", domain + ":service", principal, null);
            } catch (ResourceException ex) {
                LOGGER.error("postInstanceRefreshRequest: access check failure for {}: {}",
                        principalName, ex.getMessage());
            }
           
            if (!userRequest) {
                throw requestError("Principal mismatch: " + fullServiceName + " vs. " +
                        principalName, caller, domain, principalDomain);
            }
        }
         
        // need to verify (a) it's not a user and (b) the public key for the request
        // must match what's in the CSR. Personal domain users cannot get personal
        // TLS certificates from ZTS
        
        if (userDomain.equalsIgnoreCase(domain)) {
            throw requestError("TLS Certificates require ServiceTokens: " +
                    fullServiceName, caller, domain, principalDomain);
        }
        
        // determine if this is a refresh or initial request
        
        final Authority authority = principal.getAuthority();
        boolean refreshOperation = (!userRequest && (authority instanceof CertificateAuthority));
        
        // retrieve the public key for the request for verification
        
        final String keyId = userRequest || refreshOperation ? req.getKeyId() : principal.getKeyId();
        String publicKey = getPublicKey(domain, service, keyId);
        if (publicKey == null) {
            throw requestError("Unable to retrieve public key for " + fullServiceName +
                    " with key id: " + keyId, caller, domain, principalDomain);
        }
        
        // validate that the cn and public key match to the provided details
        
        X509CertRequest x509CertReq;
        try {
            x509CertReq = new X509CertRequest(req.getCsr());
        } catch (CryptoException ex) {
            throw requestError("Unable to parse PKCS10 certificate request",
                    caller, domain, principalDomain);
        }
        
        final PKCS10CertificationRequest certReq = x509CertReq.getCertReq();
        if (!ZTSUtils.verifyCertificateRequest(certReq, domain, service, null)) {
            throw requestError("Invalid CSR - data mismatch", caller, domain, principalDomain);
        }

        // validate that the csr contains a valid subject O field

        if (!x509CertReq.validateSubjectOField(validCertSubjectOrgValues)) {
            throw requestError("Invalid CSR - invalid Subject O field", caller, domain, principalDomain);
        }

        // validate the CSR subject ou field

        if (verifyCertSubjectOU && !x509CertReq.validateSubjectOUField(null, null,
                validCertSubjectOrgUnitValues)) {
            throw requestError("Invalid CSR - invalid Subject OU field", caller, domain, principalDomain);
        }

        // verify that the public key in the csr matches to the service
        // public key registered in Athenz
        
        if (!x509CertReq.validatePublicKeys(publicKey)) {
            throw requestError("Invalid CSR - public key mismatch", caller, domain, principalDomain);
        }

        // verify the IP address in the request matches where the connection
        // is coming from

        final String ipAddress = ServletRequestUtil.getRemoteAddress(ctx.request());
        if (verifyCertRequestIP && !x509CertReq.validateIPAddress(ipAddress)) {
            throw requestError("Invalid CSR - IP address mismatch", caller, domain, principalDomain);
        }

        // if this is not a user request and the principal authority is the
        // certificate authority then we're refreshing our certificate as
        // opposed to requesting a new one for the service so we're going
        // to do further validation based on the certificate we authenticated
        
        if (refreshOperation) {
            ServiceX509RefreshRequestStatus status =  validateServiceX509RefreshRequest(principal,
                    x509CertReq, ipAddress);
            if (status == ServiceX509RefreshRequestStatus.IP_NOT_ALLOWED) {
                throw forbiddenError("IP not allowed for refresh: " + ipAddress,
                        caller, domain, principalDomain);
            }
            if (status != ServiceX509RefreshRequestStatus.SUCCESS) {
                throw requestError("Request validation failed: " + status,
                        caller, domain, principalDomain);
            }
        }
        
        // generate identity with the certificate
        
        int expiryTime = req.getExpiryTime() != null ? req.getExpiryTime() : 0;
        Identity identity = ZTSUtils.generateIdentity(instanceCertManager, req.getCsr(),
                fullServiceName, null, expiryTime);
        if (identity == null) {
            throw serverError("Unable to generate identity", caller, domain, principalDomain);
        }
        identity.setCaCertBundle(instanceCertManager.getX509CertificateSigner());

        // log our certificate

        instanceCertManager.logX509Cert(principal, ipAddress, ZTSConsts.ZTS_SERVICE,
                ZTSUtils.extractCertReqInstanceId(certReq),
                Crypto.loadX509Certificate(identity.getCertificate()));

        return identity;
    }

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

}