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

io.helidon.security.SecurityEnvironment Maven / Gradle / Ivy

There is a newer version: 4.1.6
Show newest version
/*
 * Copyright (c) 2018, 2022 Oracle and/or its affiliates.
 *
 * 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 io.helidon.security;

import java.net.URI;
import java.time.ZonedDateTime;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.TreeMap;

import io.helidon.common.http.HashParameters;
import io.helidon.common.http.Parameters;
import io.helidon.common.http.ReadOnlyParameters;
import io.helidon.security.util.AbacSupport;

/**
 * Security environment is a set of attributes that are stable for an interaction (usually a request in our case).
 * Environment can be re-used for multiple security request (e.g authentication, authorization).
 * Access to environment is either through methods (for known attributes) or through
 * generic {@link #abacAttribute(String)} methods for any property configured by integration component.
 *
 * 

* The following properties are available (known): *

    *
  • time: decision time of the current request (e.g. when checking that this is within business hours
  • *
  • uri: target URI that was requested
  • *
  • path: path that was requested
  • *
  • method: method of the request
  • *
  • transport: transport of the request (e.g. http)
  • *
  • headers: transport headers of the request (map)
  • *
*/ public class SecurityEnvironment implements AbacSupport { private final AbacSupport properties; private final SecurityTime timeProvider; private final ZonedDateTime time; private final URI targetUri; private final String method; private final String transport; private final Optional path; private final Map> headers; private final Parameters queryParams; private SecurityEnvironment(Builder builder) { BasicAttributes basicAttributes = BasicAttributes.create(builder.attributes); this.timeProvider = builder.timeProvider; this.time = builder.time; this.targetUri = builder.targetUri; this.path = Optional.ofNullable(builder.path); this.method = builder.method; this.transport = builder.transport; Map> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); headers.putAll(builder.headers); this.headers = Collections.unmodifiableMap(headers); this.queryParams = new ReadOnlyParameters(builder.queryParams); basicAttributes.put("time", time); basicAttributes.put("uri", targetUri); basicAttributes.put("path", path); basicAttributes.put("method", method); basicAttributes.put("transport", transport); basicAttributes.put("headers", headers); this.properties = basicAttributes; } /** * Creates a fluent API builder to build new instances of this class. * * @param serverTime Time to use to obtain current time * @return a builder instance */ public static Builder builder(SecurityTime serverTime) { return new Builder(serverTime); } /** * Creates a fluent API builder to build new instances of this class with current time. * * @return a builder instance */ public static Builder builder() { return new Builder(SecurityTime.create()); } /** * Create a new instance of security environment with all default values. * * @return environment instance */ public static SecurityEnvironment create() { return builder().build(); } @Override public Object abacAttributeRaw(String key) { return properties.abacAttributeRaw(key); } @Override public Collection abacAttributeNames() { return properties.abacAttributeNames(); } /** * Time on the server this environment was created for current request. * This should be treated as the "decisive" time of the request for security evaluation. * * This can be configured - e.g. there can be a time-shift (moving time by a specific amount of seconds to the past or * to the future), or an explicit value (e.g. setting the time to 14:00 e.g. for testing purposes). * * @return server time that should be used to make security decisions * @see io.helidon.security.Security.Builder#serverTime() */ public ZonedDateTime time() { return time; } /** * Get the URI of the resource requested. For inbound request, this contains the requested URI by * remote client (or as close to the original one as we can get), for outbound requests, this contains * the actual URI as configured by client to be called on remote server. * TODO if we use service registry, we must have access to the actual endpoint (as signatures may require signing of * URI with the real host and port). Either this method MUST return a resolved URI, or we MUST have access to registry * and enforce an endpoint (when resolved). * * @return URI being called or URI to be called */ public URI targetUri() { return targetUri; } /** * Path to the resource. * For jax-rs, this is relative URI. * * @return Path to the resource */ public Optional path() { return path; } /** * Verb to execute on the resource. * For http, this is HTTP method (PUT, GET, DELETE, POST....) * * @return Verb executing on the resource, default is GET */ public String method() { return method; } /** * Return type of transport (such as http, https, jms etc.). * Transport should be case insensitive, yet I recommend using all lower case. * For the purpose of this method, http and https are two separate transports! * * @return transport used for this request. Defaults to http. */ public String transport() { return transport; } /** * Derive a new environment builder based on this environment. * * @return builder to build a new environment overriding only needed values with a new timestamp */ public Builder derive() { return builder(timeProvider) .attributes(properties) .targetUri(targetUri) .method(method) .transport(transport) .path(path.orElse(null)) .headers(headers) .queryParams(queryParams); } /** * Transport headers that can be used to process the message. * The headers stand here as a generalization - they cover all metadata sent with each request that is not * described elsewhere. * For HTTP, this would cover: all HTTP headers (done automatically by integration components), on-demand * query parameters (must be explicitly configured and supported by integration component), on-demand * form parameters (must be explicitly configured and supported by integration component). * For JMS, this would cover: all JMS headers (in string form - byte[] should be base64 encoded). * Other protocols must choose a reasonable way to transfer a request/response message into headers and entity. * * @return Header map. If transport protocol does not support headers, map will be empty */ public Map> headers() { return headers; } /** * Query parameters obtained from the request. * If transport protocol does not support query parameters, instance will be empty. * * @return query parameter instance, If transport protocol does not support query parameters, instance will be empty. */ public Parameters queryParams() { return queryParams; } /** * A fluent API builder for {@link SecurityEnvironment}. */ public static final class Builder implements io.helidon.common.Builder { /** * Default transport is {@value}. */ public static final String DEFAULT_TRANSPORT = "http"; /** * Default method is {@value}. */ public static final String DEFAULT_METHOD = "GET"; private final Map> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); private Parameters queryParams = HashParameters.create(); private SecurityTime timeProvider; private ZonedDateTime time; private BasicAttributes attributes = BasicAttributes.create(); private URI targetUri; private String path; private String method = DEFAULT_METHOD; private String transport = DEFAULT_TRANSPORT; private Builder(SecurityTime timeProvider) { this.timeProvider = timeProvider; } @Override public SecurityEnvironment build() { time = timeProvider.get(); return new SecurityEnvironment(this); } private Builder attributes(AbacSupport props) { this.attributes = BasicAttributes.create(props); return this; } /** * Add an attribute to this environment. * * @param key name of the attribute * @param value value of the attribute * @return updated builder instance */ public Builder addAttribute(String key, Object value) { this.attributes.put(key, value); return this; } /** * Transport headers (such as HTTP headers, JMS headers). * Headers are case insensitive. * * @param headers header map * @return this instance */ public Builder headers(Map> headers) { this.headers.putAll(headers); return this; } /** * We may want to clear existing headers, such as when deriving an environment * for outbound calls. * * @return this instance */ public Builder clearHeaders() { this.headers.clear(); return this; } /** * Add a single-value header. Note that if method {@link #headers(Map)} is called after * this method, it will remove changes by this method. * * @param header header name * @param value header value * @return this instance */ public Builder header(String header, String value) { this.headers.put(header, List.of(value)); return this; } /** * Add a multi-value header. Note that if method {@link #headers(Map)} is called after * this method, it may remove changes by this method. * * @param header header name * @param values header values * @return this instance */ public Builder header(String header, List values) { this.headers.put(header, values); return this; } /** * Configure target URI. * * @param uri target URI being (or to be) called. If this is an unusual protocol, build the uri following similar pattern * to HTTP (jms://host:port/connFactory/queueJndi; socket://host:port; teleport://newyork/broadway/44 * @return this instance */ public Builder targetUri(URI uri) { this.targetUri = uri; return this; } /** * Path that is requested (such as URI for http, without protocol, server and port). * * @param path the path * @return this instance */ public Builder path(String path) { this.path = path; return this; } /** * Method that is requested (such as GET/POST for http). * Default is {@value #DEFAULT_METHOD}. * * @param method the method * @return this instance */ public Builder method(String method) { this.method = method; return this; } /** * Transport we are implementing (such as http, https). * Default is {@link #DEFAULT_TRANSPORT}. * * @param transport the transport * @return this instance */ public Builder transport(String transport) { this.transport = transport; return this; } /** * Use the defined time to obtain current time. * * @param time SecurityTime that allows for explicit values being set (e.g. for unit tests) * @return updated builder instance */ public Builder time(SecurityTime time) { this.timeProvider = time; return this; } /** * Add a single-value query parameter. Note that if method {@link #queryParams(Parameters)} is called after * this method, it will remove changes by this method. * * @param paramName parameter name * @param value parameter value * @return this instance */ public Builder queryParam(String paramName, String value) { this.queryParams.put(paramName, value); return this; } /** * Add a multivalued query parameter. Note that if method {@link #queryParams(Parameters)} is called after * this method, it will remove changes by this method. * * @param paramName parameter name * @param values parameter values * @return this instance */ public Builder queryParam(String paramName, List values) { this.queryParams.put(paramName, values); return this; } /** * Add query parameters of the request. * * @param queryParams request query parameters * @return this instance */ public Builder queryParams(Parameters queryParams) { this.queryParams.putAll(queryParams); return this; } /** * We may want to clear existing query parameters. * * @return this instance */ public Builder clearQueryParams() { this.queryParams = HashParameters.create(); return this; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy