///////////////////////////////////////////////////////////////////////////////

    Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.

    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.

///////////////////////////////////////////////////////////////////////////////

= Extending Security

This guide describes how you can extend the Security component.

The component has the following extension points:

* Security providers
* Provider selection policy
* Integration with a framework

== Security providers
You can build a custom provider for each type of security concept supported.
By default, each provider is asynchronous. For simple cases, a class
exists in "spi" package to help implement a synchronous approach:
 `SynchronousProvider`.

You have two options:

1. Implement a provider interface and reference it in configuration (or from
 builder) by class
2. Implement a provider interface and provide a Java `ServiceLoader` service implementing
 `io.helidon.security.spi.SecurityProviderService`

The second option allows for easier configuration, as the configuration key can be
 used without a class definition and creates a default name of a provider.

=== Authentication provider
To create a custom authentication provider, create a class that implements
`io.helidon.security.spi.AuthenticationProvider`.
Implementation is responsible for taking a request and asserting a subject
based on that request.
In case the protocol is multi-request (e.g. challenge for basic authentication),
 you have the possibility to return specific headers and a response code. The
 default semantics of these is HTTP, though providers may exist that are not
 HTTP specific.

=== Authorization provider
To create a custom authorization provider, create a class that implements
`io.helidon.security.spi.AuthorizationProvider`.
Implementation is responsible for taking a request and checking whether the
 request can continue processing (e.g. if the current user and/or service subject
 has a right to execute it).

If authentication is configured, the Security component guarantees it resolved
 before authorization.

=== Outbound security provider
To create a custom outbound security provider, create a class that implements
`io.helidon.security.spi.OutboundSecurityProvider`.
Implementation can update outgoing message headers to handle
security for an outgoing request (e.g. identity propagation, mapping etc.).

=== Audit provider
To create a custom audit provider, create a class that implements
`io.helidon.security.spi.AuditProvider`.
Security component feeds each audit provider all messages from all components
that invoke audit method on "Security" class, including internal audit events
pre-configured in the component itself (e.g. authentication, authorization
 events).

Implementation may do whatever desired with these messages, e.g.:

* filter them
* log them
* store them to a database
* forward them to an audit component
* discard them

== Provider selection policy
Each request is processed by a single authentication and/or authorization
 provider. The selection policy provides the security component information about
 which provider to use. Out of the box, there are three policies:

1. "First" policy - first configured provider (or explicitly defined default
 provider) is used by default, if a named provider is requested, it would be used
2. "Composite" policy - this policy allows for a sequence of providers to be
 executed (e.g. one request may have more than one provider) - used for example to
 resolve service and user authentication
3. "Class" policy - this allows usage of a custom policy defined by fully
 qualified class name

To create a custom provider selection policy, create a class that implements
"io.helidon.security.spi.ProviderSelectionPolicy".

== Framework integration
The Security component supports integration with Helidon WebServer (`helidon-security-integration-webserver`)
 and with Jersey (`helidon-security-integration-jersey`).

Existing integrations (WebServer and Jersey) use Helidon Security APIs that are available to integrate any
framework/application (for example we could integrate security with messaging, such as JMS).

To create a new integration, an instance of `Security` class is needed, as it handles
all configured providers. Usually a single `Security` instance is used for an application.

`Security` is then used to create an instance of `SecurityContext`, which is used
for interaction with a single user. A single `SecurityContext` is created for each HTTP
request in Jersey and WebServer integration.

`SecurityContext` is used to invoke authentication, authorization, and outbound security requests.

Helidon Security also defines a set of annotations:

* `@Authenticated` - access to resources must follow authentication rules defined by the annotation
* `@Authorized` - access to resources must follow authorization rules defined by the annotation
* `@Audited` - to configure auditing

If the protected resources (in Helidon MP, these are JAX-RS resource classes and methods) can
be annotated, the integration component must use these annotations when deciding how to secure
the endpoint. For example, the Jersey integration checks whether the @Authenticated annotation exists. If it does, then
the integration component attempts to authenticate the request.

Because other components of Helidon Security (such as ABAC validators) query the request for annotations,
the integration component should also collect all annotations from the resource and correctly configure
them when creating the security request.