use of io.helidon.common.Errors in project helidon by oracle.
the class AbacProvider method syncAuthorize.
@Override
protected AuthorizationResponse syncAuthorize(ProviderRequest providerRequest) {
// let's find attributes to be validated
Errors.Collector collector = Errors.collector();
List<RuntimeAttribute> attributes = new ArrayList<>();
EndpointConfig epConfig = providerRequest.endpointConfig();
// list all "Attribute" annotations and make sure we support them
validateAnnotations(epConfig, collector);
// list all children of abac config and make sure one of the AbacValidators supports them
validateConfig(epConfig, collector);
// list all custom objects and check those that implement AttributeConfig and ...
validateCustom(epConfig, collector);
Optional<Config> abacConfig = epConfig.config(CONFIG_KEY);
for (var validator : validators) {
// order of preference - explicit class, configuration, annotation
Class<? extends AbacValidatorConfig> configClass = validator.configClass();
String configKey = validator.configKey();
Collection<Class<? extends Annotation>> annotations = validator.supportedAnnotations();
Optional<? extends AbacValidatorConfig> customObject = epConfig.instance(configClass);
if (customObject.isPresent()) {
attributes.add(new RuntimeAttribute(validator, customObject.get()));
} else {
// only configure this validator if its config key exists
// or it has a supported annotation
abacConfig.flatMap(it -> it.get(configKey).asNode().asOptional()).ifPresentOrElse(attribConfig -> {
attributes.add(new RuntimeAttribute(validator, validator.fromConfig(attribConfig)));
}, () -> {
List<Annotation> annotationConfig = new ArrayList<>();
for (SecurityLevel securityLevel : epConfig.securityLevels()) {
for (Class<? extends Annotation> annotation : annotations) {
List<? extends Annotation> list = securityLevel.combineAnnotations(annotation, EndpointConfig.AnnotationScope.values());
annotationConfig.addAll(list);
}
}
if (!annotationConfig.isEmpty()) {
attributes.add(new RuntimeAttribute(validator, validator.fromAnnotations(epConfig)));
}
});
}
}
for (RuntimeAttribute attribute : attributes) {
validate(attribute.getValidator(), attribute.getConfig(), collector, providerRequest);
}
Errors errors = collector.collect();
if (errors.isValid()) {
return AuthorizationResponse.permit();
}
return AuthorizationResponse.builder().status(SecurityResponse.SecurityStatus.FAILURE).description(errors.toString()).build();
}
use of io.helidon.common.Errors in project helidon by oracle.
the class SignedJwt method verifySignature.
/**
* Verify signature against the provided keys (the kid of thisPrincipal
* JWT should be present in the {@link JwkKeys} provided).
*
* @param keys JwkKeys to obtain a key to verify signature
* @param defaultJwk Default value of JWK
* @return Errors with collected messages, see {@link Errors#isValid()} and {@link Errors#checkValid()}
*/
public Errors verifySignature(JwkKeys keys, Jwk defaultJwk) {
Errors.Collector collector = Errors.collector();
String alg = headers.algorithm().orElse(null);
String kid = headers.keyId().orElse(null);
Jwk jwk = null;
boolean jwtWithoutKidAndNoneAlg = false;
// TODO support multiple JWK under same kid if different alg (see if spec allows this)
if (null == alg) {
if (null == kid) {
if (defaultJwk == null) {
jwtWithoutKidAndNoneAlg = true;
jwk = Jwk.NONE_JWK;
} else {
jwk = defaultJwk;
}
alg = jwk.algorithm();
} else {
// null alg, non-null kid - will use alg of jwk
jwk = keys.forKeyId(kid).orElse(null);
if (null == jwk) {
if (null == defaultJwk) {
collector.fatal(keys, "Key for key id: " + kid + " not found");
} else {
jwk = defaultJwk;
}
}
if (null != jwk) {
alg = jwk.algorithm();
}
}
} else {
// alg not null
if (null == kid) {
if (Jwk.ALG_NONE.equals(alg)) {
if (null != defaultJwk) {
if (defaultJwk.algorithm().equals(alg)) {
// yes, we expect none algorithm
} else {
collector.fatal("Algorithm is " + alg + ", default jwk requires " + defaultJwk.algorithm());
}
} else {
jwk = Jwk.NONE_JWK;
jwtWithoutKidAndNoneAlg = true;
}
} else {
jwk = defaultJwk;
if (null == jwk) {
collector.fatal("Algorithm is " + alg + ", yet no kid is defined in JWT header, cannot validate");
}
}
} else {
// both not null
jwk = keys.forKeyId(kid).orElse(null);
if (null == jwk) {
if ((null != defaultJwk) && alg.equals(defaultJwk.algorithm())) {
jwk = defaultJwk;
}
if (null == jwk) {
collector.fatal(keys, "Key for key id: " + kid + " not found");
}
}
}
}
if (null == jwk) {
return collector.collect();
}
if (jwtWithoutKidAndNoneAlg) {
collector.fatal(jwk, "None algorithm not allowed, unless specified as the default JWK");
}
// now if jwk algorithm is none, alg may be
if (jwk.algorithm().equals(alg)) {
try {
if (!jwk.verifySignature(signedBytes, signature)) {
collector.fatal(jwk, "Signature of JWT token is not valid, based on alg: " + alg + ", kid: " + kid);
}
} catch (Exception e) {
collector.fatal(jwk, "Failed to verify signature due to an exception: " + e.getClass().getName() + ": " + e.getMessage());
}
} else {
collector.fatal(jwk, "Algorithm of JWK (" + jwk.algorithm() + ") does not match algorithm of this JWT (" + alg + ") for kid: " + kid);
}
return collector.collect();
}
use of io.helidon.common.Errors in project helidon by oracle.
the class OidcProvider method processValidationResult.
private AuthenticationResponse processValidationResult(ProviderRequest providerRequest, SignedJwt signedJwt, Errors.Collector collector) {
Jwt jwt = signedJwt.getJwt();
Errors errors = collector.collect();
Errors validationErrors = jwt.validate(oidcConfig.issuer(), oidcConfig.audience());
if (errors.isValid() && validationErrors.isValid()) {
errors.log(LOGGER);
Subject subject = buildSubject(jwt, signedJwt);
Set<String> scopes = subject.grantsByType("scope").stream().map(Grant::getName).collect(Collectors.toSet());
// make sure we have the correct scopes
Set<String> expectedScopes = expectedScopes(providerRequest);
List<String> missingScopes = new LinkedList<>();
for (String expectedScope : expectedScopes) {
if (!scopes.contains(expectedScope)) {
missingScopes.add(expectedScope);
}
}
if (missingScopes.isEmpty()) {
return AuthenticationResponse.success(subject);
} else {
return errorResponse(providerRequest, Http.Status.FORBIDDEN_403, "insufficient_scope", "Scopes " + missingScopes + " are missing");
}
} else {
if (LOGGER.isLoggable(Level.FINEST)) {
// only log errors when details requested
errors.log(LOGGER);
validationErrors.log(LOGGER);
}
return errorResponse(providerRequest, Http.Status.UNAUTHORIZED_401, "invalid_token", "Token not valid");
}
}
use of io.helidon.common.Errors in project helidon by oracle.
the class SignedJwtTest method testSingatureNoAlgNoKid.
@Test
public void testSingatureNoAlgNoKid() {
Jwt jwt = Jwt.builder().build();
Jwk defaultJwk = Jwk.NONE_JWK;
SignedJwt signed = SignedJwt.sign(jwt, customKeys);
assertThat(signed, notNullValue());
assertThat(signed.getSignature(), notNullValue());
assertThat(signed.getSignature(), is(new byte[0]));
Errors errors = signed.verifySignature(customKeys, defaultJwk);
assertThat(errors, notNullValue());
errors.log(LOGGER);
errors.checkValid();
}
use of io.helidon.common.Errors in project helidon by oracle.
the class SignedJwtTest method testVerify.
@Test
public void testVerify() {
SignedJwt signedJwt = SignedJwt.parseToken(AUTH_0_TOKEN);
Errors errors = signedJwt.verifySignature(auth0Keys);
assertThat(errors, notNullValue());
errors.checkValid();
}
Aggregations