@Override
    public String authenticate(AuthenticationDataSource authData) throws AuthenticationException {
        SocketAddress clientAddress;
        String roleToken;
        ErrorCode errorCode = ErrorCode.UNKNOWN;
        try {

            if (authData.hasDataFromPeer()) {
                clientAddress = authData.getPeerAddress();
            } else {
                errorCode = ErrorCode.NO_CLIENT;
                throw new AuthenticationException("Authentication data source does not have a client address");
            }

            if (authData.hasDataFromCommand()) {
                roleToken = authData.getCommandData();
            } else if (authData.hasDataFromHttp()) {
                roleToken = authData.getHttpHeader(AuthZpeClient.ZPE_TOKEN_HDR);
            } else {
                errorCode = ErrorCode.NO_TOKEN;
                throw new AuthenticationException("Authentication data source does not have a role token");
            }

            if (roleToken == null) {
                errorCode = ErrorCode.NO_TOKEN;
                throw new AuthenticationException("Athenz token is null, can't authenticate");
            }
            if (roleToken.isEmpty()) {
                errorCode = ErrorCode.NO_TOKEN;
                throw new AuthenticationException("Athenz RoleToken is empty, Server is Using Athenz Authentication");
            }
            if (log.isDebugEnabled()) {
                log.debug("Athenz RoleToken : [{}] received from Client: {}", roleToken, clientAddress);
            }

            RoleToken token = new RoleToken(roleToken);

            if (!domainNameList.contains(token.getDomain())) {
                errorCode = ErrorCode.DOMAIN_MISMATCH;
                throw new AuthenticationException(
                        String.format("Athenz RoleToken Domain mismatch, Expected: %s, Found: %s",
                                domainNameList.toString(), token.getDomain()));
            }

            // Synchronize for non-thread safe static calls inside athenz library
            synchronized (this) {
                PublicKey ztsPublicKey = AuthZpeClient.getZtsPublicKey(token.getKeyId());

                if (ztsPublicKey == null) {
                    errorCode = ErrorCode.NO_PUBLIC_KEY;
                    throw new AuthenticationException("Unable to retrieve ZTS Public Key");
                }

                if (token.validate(ztsPublicKey, allowedOffset, false, null)) {
                    log.debug("Athenz Role Token : {}, Authenticated for Client: {}", roleToken, clientAddress);
                    AuthenticationMetrics.authenticateSuccess(getClass().getSimpleName(), getAuthMethodName());
                    return token.getPrincipal();
                } else {
                    errorCode = ErrorCode.INVALID_TOKEN;
                    throw new AuthenticationException(
                            String.format("Athenz Role Token Not Authenticated from Client: %s", clientAddress));
                }
            }
        } catch (AuthenticationException exception) {
            incrementFailureMetric(errorCode);
            throw exception;
        }
    }
@Test
    public void testAuthenticateSignedToken() throws Exception {

        List<String> roles = new ArrayList<String>() {
            {
                add("test_role");
            }
        };
        RoleToken token = new RoleToken.Builder("Z1", "test_provider", roles).principal("test_app").build();
        String privateKey = new String(Files.readAllBytes(Paths.get("./src/test/resources/zts_private.pem")));
        token.sign(privateKey);
        AuthenticationDataSource authData = new AuthenticationDataCommand(token.getSignedToken(),
                new InetSocketAddress("localhost", 0), null);
        assertEquals(provider.authenticate(authData), "test_app");
    }