Search in sources :

Example 6 with OAuthBearerToken

use of org.apache.kafka.common.security.oauthbearer.OAuthBearerToken in project kafka by apache.

the class OAuthBearerSaslServer method process.

private byte[] process(String tokenValue, String authorizationId, SaslExtensions extensions) throws SaslException {
    OAuthBearerValidatorCallback callback = new OAuthBearerValidatorCallback(tokenValue);
    try {
        callbackHandler.handle(new Callback[] { callback });
    } catch (IOException | UnsupportedCallbackException e) {
        handleCallbackError(e);
    }
    OAuthBearerToken token = callback.token();
    if (token == null) {
        errorMessage = jsonErrorResponse(callback.errorStatus(), callback.errorScope(), callback.errorOpenIDConfiguration());
        log.debug(errorMessage);
        return errorMessage.getBytes(StandardCharsets.UTF_8);
    }
    /*
         * We support the client specifying an authorization ID as per the SASL
         * specification, but it must match the principal name if it is specified.
         */
    if (!authorizationId.isEmpty() && !authorizationId.equals(token.principalName()))
        throw new SaslAuthenticationException(String.format("Authentication failed: Client requested an authorization id (%s) that is different from the token's principal name (%s)", authorizationId, token.principalName()));
    Map<String, String> validExtensions = processExtensions(token, extensions);
    tokenForNegotiatedProperty = token;
    this.extensions = new SaslExtensions(validExtensions);
    complete = true;
    log.debug("Successfully authenticate User={}", token.principalName());
    return new byte[0];
}
Also used : SaslExtensions(org.apache.kafka.common.security.auth.SaslExtensions) OAuthBearerToken(org.apache.kafka.common.security.oauthbearer.OAuthBearerToken) OAuthBearerValidatorCallback(org.apache.kafka.common.security.oauthbearer.OAuthBearerValidatorCallback) IOException(java.io.IOException) UnsupportedCallbackException(javax.security.auth.callback.UnsupportedCallbackException) SaslAuthenticationException(org.apache.kafka.common.errors.SaslAuthenticationException)

Example 7 with OAuthBearerToken

use of org.apache.kafka.common.security.oauthbearer.OAuthBearerToken in project kafka by apache.

the class LoginAccessTokenValidator method validate.

/**
 * Accepts an OAuth JWT access token in base-64 encoded format, validates, and returns an
 * OAuthBearerToken.
 *
 * @param accessToken Non-<code>null</code> JWT access token
 * @return {@link OAuthBearerToken}
 * @throws ValidateException Thrown on errors performing validation of given token
 */
@SuppressWarnings("unchecked")
public OAuthBearerToken validate(String accessToken) throws ValidateException {
    SerializedJwt serializedJwt = new SerializedJwt(accessToken);
    Map<String, Object> payload;
    try {
        payload = OAuthBearerUnsecuredJws.toMap(serializedJwt.getPayload());
    } catch (OAuthBearerIllegalTokenException e) {
        throw new ValidateException(String.format("Could not validate the access token: %s", e.getMessage()), e);
    }
    Object scopeRaw = getClaim(payload, scopeClaimName);
    Collection<String> scopeRawCollection;
    if (scopeRaw instanceof String)
        scopeRawCollection = Collections.singletonList((String) scopeRaw);
    else if (scopeRaw instanceof Collection)
        scopeRawCollection = (Collection<String>) scopeRaw;
    else
        scopeRawCollection = Collections.emptySet();
    Number expirationRaw = (Number) getClaim(payload, EXPIRATION_CLAIM_NAME);
    String subRaw = (String) getClaim(payload, subClaimName);
    Number issuedAtRaw = (Number) getClaim(payload, ISSUED_AT_CLAIM_NAME);
    Set<String> scopes = ClaimValidationUtils.validateScopes(scopeClaimName, scopeRawCollection);
    long expiration = ClaimValidationUtils.validateExpiration(EXPIRATION_CLAIM_NAME, expirationRaw != null ? expirationRaw.longValue() * 1000L : null);
    String subject = ClaimValidationUtils.validateSubject(subClaimName, subRaw);
    Long issuedAt = ClaimValidationUtils.validateIssuedAt(ISSUED_AT_CLAIM_NAME, issuedAtRaw != null ? issuedAtRaw.longValue() * 1000L : null);
    OAuthBearerToken token = new BasicOAuthBearerToken(accessToken, scopes, expiration, subject, issuedAt);
    return token;
}
Also used : OAuthBearerToken(org.apache.kafka.common.security.oauthbearer.OAuthBearerToken) OAuthBearerIllegalTokenException(org.apache.kafka.common.security.oauthbearer.internals.unsecured.OAuthBearerIllegalTokenException) Collection(java.util.Collection)

Example 8 with OAuthBearerToken

use of org.apache.kafka.common.security.oauthbearer.OAuthBearerToken in project kafka by apache.

the class OAuthBearerValidatorCallbackHandler method handleValidatorCallback.

private void handleValidatorCallback(OAuthBearerValidatorCallback callback) {
    checkInitialized();
    OAuthBearerToken token;
    try {
        token = accessTokenValidator.validate(callback.tokenValue());
        callback.token(token);
    } catch (ValidateException e) {
        log.warn(e.getMessage(), e);
        callback.error("invalid_token", null, null);
    }
}
Also used : OAuthBearerToken(org.apache.kafka.common.security.oauthbearer.OAuthBearerToken)

Example 9 with OAuthBearerToken

use of org.apache.kafka.common.security.oauthbearer.OAuthBearerToken in project kafka by apache.

the class OAuthBearerRefreshingLogin method configure.

@Override
public void configure(Map<String, ?> configs, String contextName, Configuration configuration, AuthenticateCallbackHandler loginCallbackHandler) {
    /*
         * Specify this class as the one to synchronize on so that only one OAuth 2
         * Bearer Token is refreshed at a given time. Specify null if we don't mind
         * multiple simultaneously refreshes. Refreshes happen on the order of minutes
         * rather than seconds or milliseconds, and there are typically minutes of
         * lifetime remaining when the refresh occurs, so serializing them seems
         * reasonable.
         */
    Class<OAuthBearerRefreshingLogin> classToSynchronizeOnPriorToRefresh = OAuthBearerRefreshingLogin.class;
    expiringCredentialRefreshingLogin = new ExpiringCredentialRefreshingLogin(contextName, configuration, new ExpiringCredentialRefreshConfig(configs, true), loginCallbackHandler, classToSynchronizeOnPriorToRefresh) {

        @Override
        public ExpiringCredential expiringCredential() {
            Set<OAuthBearerToken> privateCredentialTokens = expiringCredentialRefreshingLogin.subject().getPrivateCredentials(OAuthBearerToken.class);
            if (privateCredentialTokens.isEmpty())
                return null;
            final OAuthBearerToken token = privateCredentialTokens.iterator().next();
            if (log.isDebugEnabled())
                log.debug("Found expiring credential with principal '{}'.", token.principalName());
            return new ExpiringCredential() {

                @Override
                public String principalName() {
                    return token.principalName();
                }

                @Override
                public Long startTimeMs() {
                    return token.startTimeMs();
                }

                @Override
                public long expireTimeMs() {
                    return token.lifetimeMs();
                }

                @Override
                public Long absoluteLastRefreshTimeMs() {
                    return null;
                }
            };
        }
    };
}
Also used : ExpiringCredential(org.apache.kafka.common.security.oauthbearer.internals.expiring.ExpiringCredential) Set(java.util.Set) ExpiringCredentialRefreshingLogin(org.apache.kafka.common.security.oauthbearer.internals.expiring.ExpiringCredentialRefreshingLogin) OAuthBearerToken(org.apache.kafka.common.security.oauthbearer.OAuthBearerToken) ExpiringCredentialRefreshConfig(org.apache.kafka.common.security.oauthbearer.internals.expiring.ExpiringCredentialRefreshConfig)

Example 10 with OAuthBearerToken

use of org.apache.kafka.common.security.oauthbearer.OAuthBearerToken in project kafka by apache.

the class OAuthBearerSaslClientCallbackHandler method handleCallback.

private void handleCallback(OAuthBearerTokenCallback callback) throws IOException {
    if (callback.token() != null)
        throw new IllegalArgumentException("Callback had a token already");
    Subject subject = Subject.getSubject(AccessController.getContext());
    Set<OAuthBearerToken> privateCredentials = subject != null ? subject.getPrivateCredentials(OAuthBearerToken.class) : Collections.emptySet();
    if (privateCredentials.size() == 0)
        throw new IOException("No OAuth Bearer tokens in Subject's private credentials");
    if (privateCredentials.size() == 1)
        callback.token(privateCredentials.iterator().next());
    else {
        /*
             * There a very small window of time upon token refresh (on the order of milliseconds)
             * where both an old and a new token appear on the Subject's private credentials.
             * Rather than implement a lock to eliminate this window, we will deal with it by
             * checking for the existence of multiple tokens and choosing the one that has the
             * longest lifetime.  It is also possible that a bug could cause multiple tokens to
             * exist (e.g. KAFKA-7902), so dealing with the unlikely possibility that occurs
             * during normal operation also allows us to deal more robustly with potential bugs.
             */
        SortedSet<OAuthBearerToken> sortedByLifetime = new TreeSet<>(new Comparator<OAuthBearerToken>() {

            @Override
            public int compare(OAuthBearerToken o1, OAuthBearerToken o2) {
                return Long.compare(o1.lifetimeMs(), o2.lifetimeMs());
            }
        });
        sortedByLifetime.addAll(privateCredentials);
        log.warn("Found {} OAuth Bearer tokens in Subject's private credentials; the oldest expires at {}, will use the newest, which expires at {}", sortedByLifetime.size(), new Date(sortedByLifetime.first().lifetimeMs()), new Date(sortedByLifetime.last().lifetimeMs()));
        callback.token(sortedByLifetime.last());
    }
}
Also used : TreeSet(java.util.TreeSet) OAuthBearerToken(org.apache.kafka.common.security.oauthbearer.OAuthBearerToken) IOException(java.io.IOException) Subject(javax.security.auth.Subject) Date(java.util.Date)

Aggregations

OAuthBearerToken (org.apache.kafka.common.security.oauthbearer.OAuthBearerToken)15 Test (org.junit.jupiter.api.Test)6 IOException (java.io.IOException)2 Collection (java.util.Collection)2 TreeSet (java.util.TreeSet)2 SaslExtensions (org.apache.kafka.common.security.auth.SaslExtensions)2 OAuthBearerTokenCallback (org.apache.kafka.common.security.oauthbearer.OAuthBearerTokenCallback)2 OAuthBearerValidatorCallback (org.apache.kafka.common.security.oauthbearer.OAuthBearerValidatorCallback)2 Date (java.util.Date)1 Set (java.util.Set)1 Subject (javax.security.auth.Subject)1 UnsupportedCallbackException (javax.security.auth.callback.UnsupportedCallbackException)1 SaslAuthenticationException (org.apache.kafka.common.errors.SaslAuthenticationException)1 ExpiringCredential (org.apache.kafka.common.security.oauthbearer.internals.expiring.ExpiringCredential)1 ExpiringCredentialRefreshConfig (org.apache.kafka.common.security.oauthbearer.internals.expiring.ExpiringCredentialRefreshConfig)1 ExpiringCredentialRefreshingLogin (org.apache.kafka.common.security.oauthbearer.internals.expiring.ExpiringCredentialRefreshingLogin)1 OAuthBearerIllegalTokenException (org.apache.kafka.common.security.oauthbearer.internals.unsecured.OAuthBearerIllegalTokenException)1 JwtClaims (org.jose4j.jwt.JwtClaims)1 NumericDate (org.jose4j.jwt.NumericDate)1 InvalidJwtException (org.jose4j.jwt.consumer.InvalidJwtException)1