All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.wildfly.security.auth.realm.token.TokenSecurityRealm Maven / Gradle / Ivy

The newest version!
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2016 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.wildfly.security.auth.realm.token;

import org.wildfly.common.Assert;
import org.wildfly.security.auth.principal.NamePrincipal;
import org.wildfly.security.auth.realm.token._private.ElytronMessages;
import org.wildfly.security.auth.server.RealmIdentity;
import org.wildfly.security.auth.server.RealmUnavailableException;
import org.wildfly.security.auth.server.SecurityRealm;
import org.wildfly.security.auth.SupportLevel;
import org.wildfly.security.authz.Attributes;
import org.wildfly.security.authz.AuthorizationIdentity;
import org.wildfly.security.credential.Credential;
import org.wildfly.security.evidence.BearerTokenEvidence;
import org.wildfly.security.evidence.Evidence;

import java.security.Principal;
import java.security.spec.AlgorithmParameterSpec;
import java.util.function.Function;

/**
 * 

A {@link SecurityRealm} capable of building identities based on different security token formats based on a {@link TokenValidator}. * * @see TokenValidator * @author Pedro Igor */ public final class TokenSecurityRealm implements SecurityRealm { private final TokenValidator strategy; private final String principalClaimName; /** A function that maps the set of token claims to a Principal. */ private final Function claimToPrincipal; /** * Returns a {@link Builder} instance that can be used to configure and create a {@link TokenSecurityRealm}. * * @return the {@link Builder} */ public static Builder builder() { return new Builder(); } TokenSecurityRealm(Builder configuration) { Assert.checkNotNullParam("configuration", configuration); if (configuration.principalClaimName == null) { this.principalClaimName = "username"; } else { this.principalClaimName = configuration.principalClaimName; } if (configuration.claimToPrincipal == null) { this.claimToPrincipal = this::defaultClaimToPrincipal; } else { this.claimToPrincipal = configuration.claimToPrincipal; } this.strategy = Assert.checkNotNullParam("tokenValidationStrategy", configuration.strategy); } @Override public RealmIdentity getRealmIdentity(final Evidence evidence) { return new TokenRealmIdentity(evidence); } @Override public SupportLevel getCredentialAcquireSupport(Class credentialType, String algorithmName, final AlgorithmParameterSpec parameterSpec) throws RealmUnavailableException { return SupportLevel.UNSUPPORTED; } @Override public SupportLevel getEvidenceVerifySupport(Class evidenceType, String algorithmName) throws RealmUnavailableException { if (isBearerTokenEvidence(evidenceType)) { return SupportLevel.POSSIBLY_SUPPORTED; } return SupportLevel.UNSUPPORTED; } private boolean isBearerTokenEvidence(Evidence evidence) { return evidence != null && isBearerTokenEvidence(evidence.getClass()); } private boolean isBearerTokenEvidence(Class evidenceType) { return BearerTokenEvidence.class.equals(evidenceType); } /** * The default implementation of the claimToPrincipal mapping function. Takes the {@linkplain #principalClaimName} claim * value and wraps it in a {@linkplain NamePrincipal}. * @param claims - token claims * @return the NamePrincipal or null on failure to extract claim value */ private Principal defaultClaimToPrincipal(Attributes claims) { Principal principal = null; try { if (!claims.containsKey(principalClaimName)) { throw ElytronMessages.log.tokenRealmFailedToObtainPrincipalWithClaim(principalClaimName); } String principalName = claims.getFirst(principalClaimName); principal = new NamePrincipal(principalName); } catch (Exception e) { throw ElytronMessages.log.tokenRealmFailedToObtainPrincipal(e); } return principal; } final class TokenRealmIdentity implements RealmIdentity { private final BearerTokenEvidence evidence; private Attributes claims; TokenRealmIdentity(Evidence evidence) { if (isBearerTokenEvidence(evidence)) { this.evidence = BearerTokenEvidence.class.cast(evidence); } else { this.evidence = null; } } @Override public Principal getRealmIdentityPrincipal() { Principal principal = null; try { if (exists()) { principal = claimToPrincipal.apply(this.claims); } } catch (Exception e) { throw ElytronMessages.log.tokenRealmFailedToObtainPrincipal(e); } return principal; } @Override public boolean verifyEvidence(Evidence evidence) throws RealmUnavailableException { return validateToken(evidence) != null; } @Override public boolean exists() throws RealmUnavailableException { return getClaims() != null; } @Override public AuthorizationIdentity getAuthorizationIdentity() throws RealmUnavailableException { if (exists()) { return new AuthorizationIdentity() { @Override public Attributes getAttributes() { return claims; } }; } return null; } @Override public SupportLevel getCredentialAcquireSupport(Class credentialType, String algorithmName, final AlgorithmParameterSpec parameterSpec) throws RealmUnavailableException { return SupportLevel.UNSUPPORTED; } @Override public C getCredential(Class credentialType) throws RealmUnavailableException { return null; } @Override public SupportLevel getEvidenceVerifySupport(Class evidenceType, String algorithmName) throws RealmUnavailableException { if (isBearerTokenEvidence(evidenceType)) { return SupportLevel.SUPPORTED; } return SupportLevel.UNSUPPORTED; } private void setClaims(Attributes claims) throws RealmUnavailableException { this.claims = claims; } private Attributes getClaims() throws RealmUnavailableException { if (this.claims == null) { validateToken(this.evidence); } return this.claims; } private Attributes validateToken(Evidence evidence) throws RealmUnavailableException { if (!isBearerTokenEvidence(evidence)) { return null; } BearerTokenEvidence tokenEvidence = BearerTokenEvidence.class.cast(evidence); try { setClaims(strategy.validate(tokenEvidence)); return this.claims; } catch (RealmUnavailableException rue) { throw rue; } catch (Exception unknown) { ElytronMessages.log.debugf(unknown, "Failed to validate token evidence [%s]", tokenEvidence.getToken()); } return null; } } public static class Builder { private String principalClaimName = "username"; private Function claimToPrincipal; private TokenValidator strategy; /** * Construct a new instance. */ private Builder() { } /** * The name of the claim that should be used to obtain the principal's name. * * @param name the name of the claim that should be used to obtain the principal's name. Defaults to username * @return this instance */ public Builder principalClaimName(String name) { this.principalClaimName = name; return this; } /** * A function that maps the set of token claims to a Principal. If not specified, a function that takes the * {@linkplain #principalClaimName} claim value and wraps in in a {@linkplain NamePrincipal} is used. * @param func - the claim set to Principal mapping function. * @return the token Principal. */ public Builder claimToPrincipal(Function func) { this.claimToPrincipal = func; return this; } /** * Defines a {@link TokenValidator} that will be used to validate tokens. * * @return this instance */ public Builder validator(TokenValidator strategy) { this.strategy = strategy; return this; } /** * Creates a {@link TokenSecurityRealm} instance with all the given configuration. * * @return a new {@link TokenSecurityRealm} instance with all the given configuration */ public TokenSecurityRealm build() { return new TokenSecurityRealm(this); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy