ferris-fab-oidc 0.0.1
OpenID connection manager for Flask-AppBuilder.
License: BSD

# Flask-AppBuilder SecurityManager for OpenIDConnect

Wrapper for `flask_oidc` for usage with Flask-AppBuilder apps with roles support. When user is redirected back to application it will:

- if user with that email is not stored in DB it will be created
- if user with that email exists it will be updated (First Name, Last Name, roles)

User will be assignid with roles passed along with ID Token only if those roles are registered within FAB app. 


## Usage

### Override security_manager of Flask-Appbuilder in one of two ways

#### 1. During FAB application init

```python
from flask_appbuilder import AppBuilder
from fab_oidc.security import OIDCSecurityManager

appbuilder = AppBuilder(
    app=app,
    security_manager_class=OIDCSecurityManager,
)

```

#### 2. Via app configuration (config.py):

```python 
FAB_SECURITY_MANAGER_CLASS = 'ferris_oidc.security.OIDCSecurityManager'
```

### Create json file with parameters of IDP


```json
{
    "web": {
        "realm_public_key": "<IDP_REALM_PUBLIC_KEY>",
        "issuer": "http://<IDP_DOMAIN>/auth/realms/<IDP_REALM_PUBLIC_KEY>",
        "auth_uri": "http://<IDP_DOMAIN>/auth/realms/<IDP_REALM_PUBLIC_KEY>/protocol/openid-connect/auth",
        "client_id": "<IDP_CLIENT_ID>",
        "client_secret": "<IDP_CLIENT_SECRET>",
        "redirect_urls": [
            "http://<FAB_DOMAIN>/oidc_callback",
            "http://<FAB_DOMAIN>/login",
            
        ],
        "userinfo_uri": "http://<IDP_DOMAIN>/auth/realms/<IDP_REALM_PUBLIC_KEY>/protocol/openid-connect/userinfo",
        "token_uri": "http://<IDP_DOMAIN>/auth/realms/<IDP_REALM_PUBLIC_KEY>/protocol/openid-connect/token",
        "token_introspection_uri": "http://<IDP_DOMAIN>/auth/realms/<IDP_REALM_PUBLIC_KEY>/protocol/openid-connect/token/introspect"
    }
}
```
<br>
`IDP_REALM_PUBLIC_KEY` - public key of Keycloak Realm (explained below) <br>
`IDP_DOMAIN` - domain (and port) of Keycloak <br>
`IDP_CLIENT_ID` -  ID of keycloak client <br>
`IDP_CLIENT_SECRET` - IDP client secret <br>
`FAB_DOMAIN` - domain (and port) of FAB application<br>
<br>

If IDP is running inside docker container then value of `IDP_DOMAIN` for 

```
"userinfo_uri"
"token_uri"
"token_introspection_uri"
```

must be docker service name (and port) that is reachable from inside of other containers.


This file (e.g. `idp_config.json` should be located along with `config.py` from main FAB application, and loaded as follows:

```python
OIDC_CLIENT_SECRETS = 'idp_config.json'
```
<br> 

### Setting Identity Provider

Below are step-by-step instructions for basic Keycloak setup that is needed in order to [ferris-fab-oidc] works properly. 


#### 1. Create REALM

- Create realm that will be used
- Get realm public key and paste it in IDP config json as `REALM_PUBLIC_KEY`
    - Ralm Settings &#8594; Keys tab &#8594; Public Key


#### 2. Create Client

- Create client with following settings (replace FAB_DOMAIN with domain (and port) of your FAB application):

| Field                    | Value                              |
|--------------------------|------------------------------------|
|Client Protocol           | openid-connect                     |
|AccessType                | confidential                       |
|Root URL                  | http://<FAB_DOMAIN>/               |
|Valid Redirect URIs       | http://<FAB_DOMAIN>/oidc_callback  |
|                          | http://<FAB_DOMAIN>/login          |

- Copy client ID and paste it in IDP config json as `KEYCLOAK_CLIENT_ID`
- Copy client secret and paste it in IDP config json as `KEYCLOAK_CLIENT_SECRET`
    - Your Client &#8594; Credentials &#8594; Secret

#### 3. Create client roles that will match those used by FAB application (Admin and Public by default)

- Your Client &#8594; Roles &#8594; Add Role 
 
#### Pass roles along with other data in ID Token

- Your Client &#8594; Mappers &#8594; Add Builtin &#8594; client roles &#8594; check Add checkbox &#8594; Add Selected

Then edit created Mapper by changing following:

| Field                    | Value                              |
|--------------------------|------------------------------------|
|Token Claim Name          | roles                              |
|Add to ID token           | ON                                 |


### Create user for your Client and assign desired role of your client to it


### Add roles to id token

Client Scopes &#8594; roles (settings tab) &#8594; Include In Token Scope ON
Client Scopes &#8594; roles (mappers tab) &#8594; client roles &#8594; 
Add to ID token -> ON


<br><br><br>

#### Most of the code is from [fab_oidc](https://github.com/ministryofjustice/fab-oidc) and [fab_oidc2](https://github.com/evinaypatil/fab-oidc2). Changes are regarding confuguration (getting from app.config instead of os env variables)