Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add security context docs #77

Merged
merged 4 commits into from
Feb 28, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 45 additions & 2 deletions pages/guide/03-security.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ title: Security
API authentication is largely a solved problem and generally outside the scope of Elide.
Authorization - the act of verifying data and operation access for an _already authenticated user_ in the Elide framework involves a few core concepts:

* **User** - Each API request is associated with a user principal. The user is opaque to the Elide framework but is passed to developer-defined _check_ functions that evaluate arbitrary logic or build filter expressions.
* **User** - Each API request is associated with a user principal. The user is opaque to the Elide framework but is passed to developer-defined _check_ functions that evaluate arbitrary logic or build filter expressions. More details can be found [here](#user).
* **Checks** - a function _or_ filter expression that grants or denies a user **permission** to perform a particular action.
* **Permissions** - a set of annotations (read, update, delete, create, and share) that correspond to actions on the data model's entities and fields. Each **permission** is decorated with one or more checks that are evaluated when a user attempts to perform that action.

Expand Down Expand Up @@ -127,12 +127,55 @@ Filter expression checks are most important when a security rule is tied in some

## User
---------------------
Each request is associated with a user. The user is computed by a function that you provide conforming to the interface:
Each request is associated with a `User` object. By default the user is simply an opaque object that wraps an instance of a [SecurityContext](https://docs.oracle.com/javaee/7/api/javax/ws/rs/core/SecurityContext.html) object.

The `SecurityContext` is created outside the Elide framework in a [JAX-RS](https://jcp.org/en/jsr/detail?id=311) [ContainerRequestFilter](https://docs.oracle.com/javaee/7/api/javax/ws/rs/container/ContainerRequestFilter.html):

```java
@Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
containerRequestContext.setSecurityContext(new SecurityContext() {

...
```

This filter will typically authenticate the request and store an identifier about the user inside the new `SecurityContext`.

Elide also supports other objects besides the `SecurityContext` as the principal. You can supply any object you want by mapping the supplied
`SecurityContext` to something else. The mapping function must conform to this interface:

```java
Function<SecurityContext, Object>
```

The JSON-API and GraphQL JAX-RS endpoints are injected with this function during initialization:

```java
@Inject
public JsonApiEndpoint(@Named("elide") Elide elide,
@Named("elideUserExtractionFunction") DefaultOpaqueUserFunction getUser) {
```

```java
@Inject
public GraphQLEndpoint(
@Named("elide") Elide elide,
@Named("elideUserExtractionFunction") DefaultOpaqueUserFunction getUser) {
```

The Elide standalone repository overrides the default to map the `SecurityContext` to a [Principal](https://docs.oracle.com/javase/10/docs/api/java/security/Principal.html) object instead:

```java
/**
* The function used to extract a user from the SecurityContext.
*
* @return Function for user extraction.
*/
default DefaultOpaqueUserFunction getUserExtractionFunction() {
return SecurityContext::getUserPrincipal;
}
```

## Permission Annotations
---------------------
The permission annotations include `ReadPermission`, `UpdatePermission`, `CreatePermission`, `DeletePermission`, and `SharePermission`. Permissions are annotations which can be applied to a model at the `package`, `entity`, or `field`-level. The most specific annotation always take precedence (`package < entity < field`). More specifically, a field annotation overrides the behavior of an entity annotation. An entity annotation overrides the behavior of a package annotation. Entity annotations can be inherited from superclasses. When no annotation is provided at any level, access is implicitly granted for `ReadPermission`, `UpdatePermission`, `CreatePermission`, and `DeletePermission` and implicitly denied for `SharePermission`.
Expand Down