use of org.dcache.auth.BearerTokenCredential in project dcache by dCache.
the class CopyFilter method fetchCredential.
private Object fetchCredential(CredentialSource source) throws InterruptedException, ErrorResponseException {
Subject subject = Subject.getSubject(AccessController.getContext());
switch(source) {
case GRIDSITE:
try {
HttpServletRequest request = ServletRequest.getRequest();
// Use the X.509 identity from TLS, even if that wasn't used to
// establish the user's identity. This allows the local activity of
// the COPY (i.e., the ability to read a file, or create a new file)
// to be authorized based on some non-X.509 identity, while using a
// delegated X.509 credential when authenticating for the
// third-party copy, based on the client credential presented when
// establishing the TLS connection.
Subject x509Subject = AuthenticationHandler.getX509Identity(request);
String dn = x509Subject == null ? null : Subjects.getDn(x509Subject);
if (dn == null) {
throw new ErrorResponseException(Response.Status.SC_UNAUTHORIZED, "user must present valid X.509 certificate");
}
String fqan = Objects.toString(Subjects.getPrimaryFqan(x509Subject), null);
/* If delegation has been requested and declined then
* potentially use the existing delegated credential. We don't
* want to artifically fail requests that might otherwise
* succeed.
*/
int minLifetimeInMinutes = hasClientAlreadyBeenRedirected(request) ? 2 : 20;
return _credentialService.getDelegatedCredential(dn, fqan, minLifetimeInMinutes, MINUTES);
} catch (PermissionDeniedCacheException e) {
throw new ErrorResponseException(Status.SC_UNAUTHORIZED, "Presented X.509 certificate not valid");
} catch (CacheException e) {
throw new ErrorResponseException(Status.SC_INTERNAL_SERVER_ERROR, "Internal problem: " + e.getMessage());
}
case OIDC:
BearerTokenCredential bearer = subject.getPrivateCredentials().stream().filter(BearerTokenCredential.class::isInstance).map(BearerTokenCredential.class::cast).findFirst().orElseThrow(() -> new ErrorResponseException(Status.SC_UNAUTHORIZED, "User must authenticate with OpenID for " + "OpenID delegation"));
return _credentialService.getDelegatedCredential(bearer.getToken(), _oidcClientCredentials);
case NONE:
return null;
default:
throw new RuntimeException("Unsupported source " + source);
}
}
use of org.dcache.auth.BearerTokenCredential in project dcache by dCache.
the class SciTokenPlugin method authenticate.
@Override
public void authenticate(Set<Object> publicCredentials, Set<Object> privateCredentials, Set<Principal> identifiedPrincipals, Set<Restriction> restrictions) throws AuthenticationException {
List<String> tokens = privateCredentials.stream().filter(BearerTokenCredential.class::isInstance).map(BearerTokenCredential.class::cast).map(BearerTokenCredential::getToken).filter(JsonWebToken::isCompatibleFormat).collect(Collectors.toList());
checkAuthentication(!tokens.isEmpty(), "no JWT bearer token");
checkAuthentication(tokens.size() == 1, "multiple JWT bearer tokens");
try {
JsonWebToken token = checkValid(new JsonWebToken(tokens.get(0)));
Issuer issuer = issuerOf(token);
validateWlcgVersionClaim(token);
Collection<Principal> principals = new ArrayList<>();
// REVISIT consider introducing an SPI to allow plugable support for handling claims.
Optional<String> sub = token.getPayloadString("sub");
sub.map(s -> new JwtSubPrincipal(issuer.getId(), s)).ifPresent(principals::add);
sub.map(s -> new OidcSubjectPrincipal(s, issuer.getId())).ifPresent(principals::add);
Optional<String> jti = token.getPayloadString("jti");
jti.map(s -> new JwtJtiPrincipal(issuer.getId(), s)).ifPresent(principals::add);
token.getPayloadStringOrArray("wlcg.groups").stream().map(OpenIdGroupPrincipal::new).forEach(principals::add);
checkAuthentication(sub.isPresent() || jti.isPresent(), "missing sub and jti claims");
principals.add(issuer.getOpIdentity());
List<AuthorisationSupplier> scopes = token.getPayloadString("scope").map(SciTokenPlugin::parseScope).orElse(Collections.emptyList());
if (scopes.isEmpty()) {
// No scopes defined -> not explicit authorisation; however, perhaps the client
// is allowed to do something based on asserted group-membership or from their
// membership of the VO (implied by the OP issuing any token at all).
// This only makes sense if the token follows the WLCG AuthZ profile. A SciToken
// is not valid (or useful) without at least one authorisation statements in the
// 'scope' claim
checkAuthentication(token.getPayloadString("wlcg.ver").isPresent(), "not a SciToken or WLCG profile.");
// allow login to proceed with whatever information we've gained so far.
} else {
principals.addAll(issuer.getUserIdentity());
Restriction r = buildRestriction(issuer.getPrefix(), scopes);
LOGGER.debug("Authenticated user with restriction: {}", r);
restrictions.add(r);
principals.add(new ExemptFromNamespaceChecks());
}
identifiedPrincipals.addAll(principals);
} catch (IOException e) {
throw new AuthenticationException(e.getMessage());
}
}
use of org.dcache.auth.BearerTokenCredential in project dcache by dCache.
the class GplazmaLoginSciTokenValidator method validate.
@Override
public void validate(ChannelHandlerContext ctx, String token) throws XrootdException {
Subject tokenSubject = new Subject();
tokenSubject.getPrivateCredentials().add(new BearerTokenCredential(token));
LoginReply loginReply;
try {
LOGGER.debug("getting login reply with: {}.", tokenSubject.getPrivateCredentials());
loginReply = loginStrategy.login(tokenSubject);
} catch (PermissionDeniedCacheException e) {
throw new XrootdException(kXR_NotAuthorized, e.toString());
} catch (CacheException e) {
throw new XrootdException(kXR_ServerError, e.toString());
}
/**
* It is possible the the user is already logged in via a standard
* authentication protocol. In that case, the XrootdRedirectHandler
* in the door already has stored a Restriction object and user
* metadata. This needs to be overwritten with the current values.
*/
LOGGER.debug("notifying door of new login reply: {}.", loginReply);
ctx.fireUserEventTriggered(new LoginEvent(loginReply));
}
use of org.dcache.auth.BearerTokenCredential in project dcache by dCache.
the class AuthenticationHandler method addAuthCredentialsToSubject.
private void addAuthCredentialsToSubject(HttpServletRequest request, Subject subject) throws PermissionDeniedCacheException {
Optional<AuthInfo> optional = parseAuthenticationHeader(request);
if (optional.isPresent()) {
AuthInfo info = optional.get();
switch(info.getScheme()) {
case HttpServletRequest.BASIC_AUTH:
if (!_isBasicAuthenticationEnabled) {
return;
}
try {
byte[] bytes = Base64.getDecoder().decode(info.getData().getBytes(StandardCharsets.US_ASCII));
String credential = new String(bytes, StandardCharsets.UTF_8);
int colon = credential.indexOf(":");
if (colon >= 0) {
String user = credential.substring(0, colon);
int lastHash = user.lastIndexOf('#');
if (lastHash != -1 && lastHash < (user.length() - 1)) {
Splitter.on(',').trimResults().omitEmptyStrings().split(user.substring(lastHash + 1)).forEach(r -> subject.getPrincipals().add(new DesiredRole(r)));
user = user.substring(0, lastHash);
}
String password = credential.substring(colon + 1);
subject.getPrivateCredentials().add(new PasswordCredential(user, password));
} else {
subject.getPrincipals().add(new LoginNamePrincipal(credential));
}
} catch (IllegalArgumentException e) {
LOG.warn("Authentication Data in the header received is not Base64 encoded {}", request.getHeader("Authorization"));
}
break;
case "BEARER":
if (!_acceptBearerTokenUnencrypted && !request.isSecure()) {
throw new PermissionDeniedCacheException("not allowed to send bearer token unencrypted");
}
try {
subject.getPrivateCredentials().add(new BearerTokenCredential(info.getData()));
} catch (IllegalArgumentException e) {
LOG.info("Bearer Token in invalid {}", request.getHeader("Authorization"));
}
break;
default:
LOG.debug("Unknown authentication scheme {}", info.getScheme());
}
}
}
use of org.dcache.auth.BearerTokenCredential in project dcache by dCache.
the class OidcAuthPlugin method authenticate.
@Override
public void authenticate(Set<Object> publicCredentials, Set<Object> privateCredentials, Set<Principal> identifiedPrincipals, Set<Restriction> restrictions) throws AuthenticationException {
String token = null;
for (Object credential : privateCredentials) {
if (credential instanceof BearerTokenCredential) {
checkAuthentication(token == null, "Multiple bearer tokens");
token = ((BearerTokenCredential) credential).getToken();
LOG.debug("Found bearer token: {}", token);
}
}
checkAuthentication(token != null, "No bearer token in the credentials");
checkValid(token);
try {
ExtractResult result = tokenProcessor.extract(token);
checkAuthentication(!result.claims().isEmpty(), "processing token yielded no claims");
checkAudience(result.claims());
var idp = result.idp();
identifiedPrincipals.add(new OAuthProviderPrincipal(idp.getName()));
Profile profile = idp.getProfile();
var profileResult = profile.processClaims(idp, result.claims());
identifiedPrincipals.addAll(profileResult.getPrincipals());
profileResult.getRestriction().ifPresent(restrictions::add);
} catch (UnableToProcess e) {
throw new AuthenticationException("Unable to process token: " + e.getMessage());
}
}
Aggregations