@Override protected AuthenticationResponse syncAuthenticate(ProviderRequest providerRequest) { Map<String, List<String>> headers = providerRequest.env().headers(); List<String> authorizationHeader = headers.get(HEADER_AUTHENTICATION); if (null == authorizationHeader) { return fail("No " + HEADER_AUTHENTICATION + " header"); } return authorizationHeader.stream() .filter(header -> header.toLowerCase().startsWith(DIGEST_PREFIX)) .findFirst() .map(value -> validateDigestAuth(value, providerRequest.env())) .orElseGet(() -> fail("Authorization header does not contain digest authentication: " + authorizationHeader)); }
@Override public boolean isOutboundSupported(ProviderRequest providerRequest, SecurityEnvironment outboundEnv, EndpointConfig outboundConfig) { return providerRequest.securityContext() .user() .flatMap(subject -> subject.publicCredential(TokenCredential.class)) .flatMap(token -> token.getIssuer() .map(issuer -> issuer.endsWith(".google.com"))) .orElse(false); }
private Set<String> expectedScopes(ProviderRequest request) { List<ScopeValidator.Scopes> expectedScopes = request.endpointConfig() .combineAnnotations(ScopeValidator.Scopes.class, EndpointConfig.AnnotationScope.values()); Set<String> result = new HashSet<>(); expectedScopes.stream() .map(ScopeValidator.Scopes::value) .map(Arrays::asList) .map(List::stream) .forEach(stream -> stream.map(ScopeValidator.Scope::value) .forEach(result::add)); return result; }
@Override public CompletionStage<AuthenticationResponse> authenticate(ProviderRequest providerRequest) { Map<String, List<String>> headers = providerRequest.env().headers(); if ((headers.get("Signature") != null) && acceptHeaders.contains(HttpSignHeader.SIGNATURE)) { return CompletableFuture .supplyAsync(() -> signatureHeader(headers.get("Signature"), providerRequest.env()), providerRequest.securityContext().executorService()); } else if ((headers.get("Authorization") != null) && acceptHeaders.contains(HttpSignHeader.AUTHORIZATION)) { // TODO when authorization header in use and "authorization" is also a // required header to be signed, we must either fail or ignore, as we cannot sign ourselves return CompletableFuture .supplyAsync(() -> authorizeHeader(providerRequest.env()), providerRequest.securityContext().executorService()); } if (optional) { return CompletableFuture.completedFuture(AuthenticationResponse.abstain()); } return CompletableFuture .completedFuture(AuthenticationResponse.failed("Missing header. Accepted headers: " + acceptHeaders)); }
@Override public void executePolicy(String policyStatement, Errors.Collector collector, ProviderRequest request) { StandardELContext context = new StandardELContext(ef); context.addELResolver(ATTRIBUTE_RESOLVER); FunctionMapper functions = context.getFunctionMapper(); VariableMapper variables = context.getVariableMapper(); customMethods.forEach(customFunction -> functions.mapFunction(customFunction.prefix, customFunction.localName, customFunction.method)); Subject userSubject = request.subject().orElse(SecurityContext.ANONYMOUS); variable(variables, "user", userSubject, Subject.class); variable(variables, "subject", userSubject, Subject.class); variable(variables, "service", request.service().orElse(SecurityContext.ANONYMOUS), Subject.class); variable(variables, "env", request.env(), SecurityEnvironment.class); variable(variables, "object", request.getObject().orElse(null), Object.class); variable(variables, "request", request, ProviderRequest.class); try { ValueExpression expression = ef.createValueExpression(context, policyStatement, boolean.class); boolean value = (boolean) expression.getValue(context); if (!value) { collector.fatal(this, "Policy statement \"" + policyStatement + "\" evaluated to false"); } } catch (Exception e) { collector.fatal(this, "Policy statement \"" + policyStatement + "\" evaluated to an exception " + e.getClass() .getName() + " with message: " + e.getMessage()); LOGGER.log(Level.FINEST, e, () -> "Statement " + policyStatement + " evaluation failed"); } }
@Override public void validate(RoleConfig config, Errors.Collector collector, ProviderRequest request) { if (config.denyAll()) { collector.fatal(this, "Access denied by DenyAll."); return; } if (config.permitAll()) { return; } validate(config.userRolesAllowed(), collector, request.subject(), SubjectType.USER); validate(config.serviceRolesAllowed(), collector, request.service(), SubjectType.SERVICE); }
@Override public void executePolicy(String policyStatement, Errors.Collector collector, ProviderRequest request) { StandardELContext context = new StandardELContext(ef); context.addELResolver(ATTRIBUTE_RESOLVER); FunctionMapper functions = context.getFunctionMapper(); VariableMapper variables = context.getVariableMapper(); customMethods.forEach(customFunction -> functions.mapFunction(customFunction.prefix, customFunction.localName, customFunction.method)); Subject userSubject = request.getSubject().orElse(SecurityContext.ANONYMOUS); variable(variables, "user", userSubject, Subject.class); variable(variables, "subject", userSubject, Subject.class); variable(variables, "service", request.getService().orElse(SecurityContext.ANONYMOUS), Subject.class); variable(variables, "env", request.getEnv(), SecurityEnvironment.class); variable(variables, "object", request.getObject().orElse(null), Object.class); variable(variables, "request", request, ProviderRequest.class); try { ValueExpression expression = ef.createValueExpression(context, policyStatement, boolean.class); boolean value = (boolean) expression.getValue(context); if (!value) { collector.fatal(this, "Policy statement \"" + policyStatement + "\" evaluated to false"); } } catch (Exception e) { collector.fatal(this, "Policy statement \"" + policyStatement + "\" evaluated to an exception " + e.getClass() .getName() + " with message: " + e.getMessage()); LOGGER.log(Level.FINEST, e, () -> "Statement " + policyStatement + " evaluation failed"); } }
@Override public void validate(ScopesConfig config, Errors.Collector collector, ProviderRequest request) { OptionalHelper.from(request.subject()).ifPresentOrElse( subject -> { Set<String> requiredScopes = new LinkedHashSet<>(config.requiredScopes());
@Override protected AuthenticationResponse syncAuthenticate(ProviderRequest providerRequest) { if (!authenticate) { return AuthenticationResponse.abstain(); } Optional<String> username = atnTokenHandler.extractToken(providerRequest.getEnv().getHeaders()); return username .map(Principal::create) .map(principal -> { if (subjectType == SubjectType.USER) { return AuthenticationResponse.success(principal); } else { return AuthenticationResponse.successService(principal); } }) .orElseGet(() -> { if (optional) { return AuthenticationResponse.abstain(); } else { return AuthenticationResponse.failed("Header not available or in a wrong format"); } } ); }
@Override protected AuthenticationResponse syncAuthenticate(ProviderRequest providerRequest) { Optional<String> maybeToken; try { maybeToken = tokenHandler.extractToken(providerRequest.env().headers()); } catch (Exception e) { return failInvalidRequest(e); } SecurityContext sContext = providerRequest.securityContext(); return maybeToken .map(token -> cachedResponse(token, sContext.tracer(), sContext.tracingSpan())) .orElseGet(this::failNoToken); }
@Override public void executePolicy(String policyStatement, Errors.Collector collector, ProviderRequest request) { StandardELContext context = new StandardELContext(ef); context.addELResolver(ATTRIBUTE_RESOLVER); FunctionMapper functions = context.getFunctionMapper(); VariableMapper variables = context.getVariableMapper(); customMethods.forEach(customFunction -> functions.mapFunction(customFunction.prefix, customFunction.localName, customFunction.method)); Subject userSubject = request.subject().orElse(SecurityContext.ANONYMOUS); variable(variables, "user", userSubject, Subject.class); variable(variables, "subject", userSubject, Subject.class); variable(variables, "service", request.service().orElse(SecurityContext.ANONYMOUS), Subject.class); variable(variables, "env", request.env(), SecurityEnvironment.class); variable(variables, "object", request.getObject().orElse(null), Object.class); variable(variables, "request", request, ProviderRequest.class); try { ValueExpression expression = ef.createValueExpression(context, policyStatement, boolean.class); boolean value = (boolean) expression.getValue(context); if (!value) { collector.fatal(this, "Policy statement \"" + policyStatement + "\" evaluated to false"); } } catch (Exception e) { collector.fatal(this, "Policy statement \"" + policyStatement + "\" evaluated to an exception " + e.getClass() .getName() + " with message: " + e.getMessage()); LOGGER.log(Level.FINEST, e, () -> "Statement " + policyStatement + " evaluation failed"); } }
@Override public void validate(ScopesConfig config, Errors.Collector collector, ProviderRequest request) { OptionalHelper.from(request.subject()).ifPresentOrElse( subject -> { Set<String> requiredScopes = new LinkedHashSet<>(config.requiredScopes());
private String origUri(ProviderRequest providerRequest) { List<String> origUri = providerRequest.env().headers() .getOrDefault(Security.HEADER_ORIG_URI, CollectionsHelper.listOf()); if (origUri.isEmpty()) { origUri = CollectionsHelper.listOf(providerRequest.env().targetUri().getPath()); } try { return URLEncoder.encode(origUri.get(0), "UTF-8"); } catch (UnsupportedEncodingException e) { throw new SecurityException("UTF-8 must be supported for security to work", e); } }
@Override public CompletionStage<OutboundSecurityResponse> outboundSecurity(ProviderRequest providerRequest, SecurityEnvironment outboundEnv, EndpointConfig outboundConfig) { return CompletableFuture.supplyAsync(() -> signRequest(outboundEnv), providerRequest.securityContext().executorService()); }
@Override protected AuthenticationResponse syncAuthenticate(ProviderRequest providerRequest) { if (!authenticate) { return AuthenticationResponse.abstain(); } List<LoginConfig> loginConfigs = providerRequest.endpointConfig() .combineAnnotations(LoginConfig.class, EndpointConfig.AnnotationScope.APPLICATION); try { return loginConfigs.stream() .filter(JwtAuthAnnotationAnalyzer::isMpJwt) .findFirst() .map(loginConfig -> authenticate(providerRequest, loginConfig)) .orElseGet(AuthenticationResponse::abstain); } catch (java.lang.SecurityException e) { return AuthenticationResponse.failed("Failed to process authentication header", e); } }
@Override protected AuthenticationResponse syncAuthenticate(ProviderRequest providerRequest) { Map<String, List<String>> headers = providerRequest.env().headers(); List<String> authorizationHeader = headers.get(HEADER_AUTHENTICATION); if (null == authorizationHeader) { return fail("No " + HEADER_AUTHENTICATION + " header"); } return authorizationHeader.stream() .filter(header -> header.toLowerCase().startsWith(BASIC_PREFIX)) .findFirst() .map(this::validateBasicAuth) .orElseGet(() -> fail("Authorization header does not contain basic authentication: " + authorizationHeader)); }
/** * Authorize a request based on configuration. * * Authorization cannot be optional. If this method is called, it should always attempt to authorize the current request. * This method will be invoked for inbound requests ONLY. * * @param providerRequest context of this security enforcement/validation * @return response that either permits, denies or abstains from decision * @see AuthorizationResponse#permit() */ public final CompletionStage<AuthorizationResponse> authorize(ProviderRequest providerRequest) { return CompletableFuture.supplyAsync(() -> syncAuthorize(providerRequest), providerRequest.securityContext().executorService()); }
List<RuntimeAttribute> attributes = new ArrayList<>(); EndpointConfig epConfig = providerRequest.endpointConfig();
@Override public void validate(TimeConfig config, Errors.Collector collector, ProviderRequest request) { ZonedDateTime now = request.env().time(); config.validate(this, now, collector); }