Skip to content

Commit

Permalink
feat: introduce new hybrid persistence mapping (#1505)
Browse files Browse the repository at this point in the history
* test: set extra verbosity to run pytest

* refactor: initial work on additional hybrid persistence

* refactor: use PersistenceMapper class to handle hybrid mapping

* refactor: modify wait_for functions to conform to persistence mapper

* test(tox): add posargs to customize running testcases

* refactor: add shortcuts to wait_for_persistence* functions

* feat: add new hybrid persistence for persistence-loader and auth-server

* fix: add missing configuration files for persistence

* feat: add new hybrid persistence for auth-server and config-api

* feat: add new hybrid persistence for scim and fido2

* feat: add new hybrid persistence for certmanager

* feat: add new hybrid persistence for client-api and persistence-loader

* docs: add Hybrid mapping section

* fix: couchbase persistence helpers for hybrid mapping

* fix: couchbase_setup module for hybrid mapping

* refactor: remove code smells reported by sonarcloud.io

* chore(jans-pycloudlib): updated build (#1506)

Co-authored-by: mo-auto <54212639+mo-auto@users.noreply.github.com>
  • Loading branch information
iromli and mo-auto committed Jun 6, 2022
1 parent b70fc52 commit a77ab60
Show file tree
Hide file tree
Showing 58 changed files with 1,569 additions and 863 deletions.
2 changes: 1 addition & 1 deletion docker-jans-auth-server/Dockerfile
Expand Up @@ -195,7 +195,7 @@ ENV CN_SECRET_ADAPTER=vault \
# ===============

ENV CN_PERSISTENCE_TYPE=ldap \
CN_PERSISTENCE_LDAP_MAPPING=default \
CN_HYBRID_MAPPING="{}" \
CN_LDAP_URL=localhost:1636 \
CN_LDAP_USE_SSL=true \
CN_COUCHBASE_URL=localhost \
Expand Down
44 changes: 38 additions & 6 deletions docker-jans-auth-server/README.md
Expand Up @@ -47,13 +47,13 @@ The following environment variables are supported by the container:
- `CN_MAX_RAM_PERCENTAGE`: Value passed to Java option `-XX:MaxRAMPercentage`.
- `CN_DEBUG_PORT`: port of remote debugging (if omitted, remote debugging will be disabled).
- `CN_PERSISTENCE_TYPE`: Persistence backend being used (one of `ldap`, `couchbase`, or `hybrid`; default to `ldap`).
- `CN_PERSISTENCE_LDAP_MAPPING`: Specify data that should be saved in LDAP (one of `default`, `user`, `cache`, `site`, `token`, or `session`; default to `default`). Note this environment only takes effect when `CN_PERSISTENCE_TYPE` is set to `hybrid`.
- `CN_LDAP_URL`: Address and port of LDAP server (default to `localhost:1636`); required if `CN_PERSISTENCE_TYPE` is set to `ldap` or `hybrid`.
- `CN_HYBRID_MAPPING`: Specify data mapping for each persistence (default to `"{}"`). Note this environment only takes effect when `CN_PERSISTENCE_TYPE` is set to `hybrid`. See [hybrid mapping](#hybrid-mapping) section for details.
- `CN_LDAP_URL`: Address and port of LDAP server (default to `localhost:1636`).
- `CN_LDAP_USE_SSL`: Whether to use SSL connection to LDAP server (default to `true`).
- `CN_COUCHBASE_URL`: Address of Couchbase server (default to `localhost`); required if `CN_PERSISTENCE_TYPE` is set to `couchbase` or `hybrid`.
- `CN_COUCHBASE_USER`: Username of Couchbase server (default to `admin`); required if `CN_PERSISTENCE_TYPE` is set to `couchbase` or `hybrid`.
- `CN_COUCHBASE_CERT_FILE`: Couchbase root certificate location (default to `/etc/certs/couchbase.crt`); required if `CN_PERSISTENCE_TYPE` is set to `couchbase` or `hybrid`.
- `CN_COUCHBASE_PASSWORD_FILE`: Path to file contains Couchbase password (default to `/etc/jans/conf/couchbase_password`); required if `CN_PERSISTENCE_TYPE` is set to `couchbase` or `hybrid`.
- `CN_COUCHBASE_URL`: Address of Couchbase server (default to `localhost`).
- `CN_COUCHBASE_USER`: Username of Couchbase server (default to `admin`).
- `CN_COUCHBASE_CERT_FILE`: Couchbase root certificate location (default to `/etc/certs/couchbase.crt`).
- `CN_COUCHBASE_PASSWORD_FILE`: Path to file contains Couchbase password (default to `/etc/jans/conf/couchbase_password`).
- `CN_COUCHBASE_CONN_TIMEOUT`: Connect timeout used when a bucket is opened (default to `10000` milliseconds).
- `CN_COUCHBASE_CONN_MAX_WAIT`: Maximum time to wait before retrying connection (default to `20000` milliseconds).
- `CN_COUCHBASE_SCAN_CONSISTENCY`: Default scan consistency; one of `not_bounded`, `request_plus`, or `statement_plus` (default to `not_bounded`).
Expand Down Expand Up @@ -114,3 +114,35 @@ The following key-value pairs are the defaults:
"audit_log_level": "INFO"
}
```

### Hybrid mapping

As per v1.0.1, hybrid persistence supports all available persistence types. To configure hybrid persistence and its data mapping, follow steps below:

1. Set `CN_PERSISTENCE_TYPE` environment variable to `hybrid`

1. Set `CN_HYBRID_MAPPING` with the following format:

```
{
"default": "<couchbase|ldap|spanner|sql>",
"user": "<couchbase|ldap|spanner|sql>",
"site": "<couchbase|ldap|spanner|sql>",
"cache": "<couchbase|ldap|spanner|sql>",
"token": "<couchbase|ldap|spanner|sql>",
"session": "<couchbase|ldap|spanner|sql>",
}
```

Example:

```
{
"default": "sql",
"user": "spanner",
"site": "ldap",
"cache": "sql",
"token": "couchbase",
"session": "spanner",
}
```
2 changes: 1 addition & 1 deletion docker-jans-auth-server/requirements.txt
@@ -1,4 +1,4 @@
# pinned to py3-grpcio version to avoid failure on native extension build
grpcio==1.41.0
libcst<0.4
git+https://github.com/JanssenProject/jans@89859286d69e7de7885bd9da9f50720c8371e797#egg=jans-pycloudlib&subdirectory=jans-pycloudlib
git+https://github.com/JanssenProject/jans@a0b7eac21ab3e405ad60e913f966476c34420c62#egg=jans-pycloudlib&subdirectory=jans-pycloudlib
18 changes: 11 additions & 7 deletions docker-jans-auth-server/scripts/bootstrap.py
Expand Up @@ -16,6 +16,7 @@
from jans.pycloudlib.persistence import sync_ldap_truststore
from jans.pycloudlib.persistence import render_sql_properties
from jans.pycloudlib.persistence import render_spanner_properties
from jans.pycloudlib.persistence.utils import PersistenceMapper
from jans.pycloudlib.utils import cert_to_truststore
from jans.pycloudlib.utils import get_server_certificate
from jans.pycloudlib.utils import generate_keystore
Expand Down Expand Up @@ -71,15 +72,21 @@ def main():
render_salt(manager, "/app/templates/salt.tmpl", "/etc/jans/conf/salt")
render_base_properties("/app/templates/jans.properties.tmpl", "/etc/jans/conf/jans.properties")

if persistence_type in ("ldap", "hybrid"):
mapper = PersistenceMapper()
persistence_groups = mapper.groups().keys()

if persistence_type == "hybrid":
render_hybrid_properties("/etc/jans/conf/jans-hybrid.properties")

if "ldap" in persistence_groups:
render_ldap_properties(
manager,
"/app/templates/jans-ldap.properties.tmpl",
"/etc/jans/conf/jans-ldap.properties",
)
sync_ldap_truststore(manager)

if persistence_type in ("couchbase", "hybrid"):
if "couchbase" in persistence_groups:
render_couchbase_properties(
manager,
"/app/templates/jans-couchbase.properties.tmpl",
Expand All @@ -89,17 +96,14 @@ def main():
# sync_couchbase_cert(manager)
sync_couchbase_truststore(manager)

if persistence_type == "hybrid":
render_hybrid_properties("/etc/jans/conf/jans-hybrid.properties")

if persistence_type == "sql":
if "sql" in persistence_groups:
render_sql_properties(
manager,
"/app/templates/jans-sql.properties.tmpl",
"/etc/jans/conf/jans-sql.properties",
)

if persistence_type == "spanner":
if "spanner" in persistence_groups:
render_spanner_properties(
manager,
"/app/templates/jans-spanner.properties.tmpl",
Expand Down
14 changes: 3 additions & 11 deletions docker-jans-auth-server/scripts/keystore_mod.py
Expand Up @@ -5,6 +5,7 @@
from jans.pycloudlib.persistence.ldap import LdapClient
from jans.pycloudlib.persistence.sql import SqlClient
from jans.pycloudlib.persistence.spanner import SpannerClient
from jans.pycloudlib.persistence.utils import PersistenceMapper


class BasePersistence:
Expand Down Expand Up @@ -122,17 +123,8 @@ def __init__(self, manager):


def modify_keystore_path(manager, path, jwks_uri):
persistence_type = os.environ.get("CN_PERSISTENCE_TYPE", "ldap")
ldap_mapping = os.environ.get("CN_PERSISTENCE_LDAP_MAPPING", "default")

if persistence_type in ("ldap", "couchbase", "sql", "spanner"):
backend_type = persistence_type
else:
# persistence_type is hybrid
if ldap_mapping == "default":
backend_type = "ldap"
else:
backend_type = "couchbase"
mapper = PersistenceMapper()
backend_type = mapper.mapping["default"]

# resolve backend
backend = _backend_classes[backend_type](manager)
Expand Down
21 changes: 5 additions & 16 deletions docker-jans-auth-server/scripts/wait.py
@@ -1,39 +1,28 @@
import logging
import logging.config
import os

from jans.pycloudlib import get_manager
from jans.pycloudlib import wait_for
from jans.pycloudlib import wait_for_persistence
from jans.pycloudlib.validators import validate_persistence_type
from jans.pycloudlib.validators import validate_persistence_ldap_mapping
from jans.pycloudlib.validators import validate_persistence_hybrid_mapping
from jans.pycloudlib.validators import validate_persistence_sql_dialect

from settings import LOGGING_CONFIG

logging.config.dictConfig(LOGGING_CONFIG)
logger = logging.getLogger("wait")


def main():
persistence_type = os.environ.get("CN_PERSISTENCE_TYPE", "ldap")
validate_persistence_type(persistence_type)

ldap_mapping = os.environ.get("CN_PERSISTENCE_LDAP_MAPPING", "default")
validate_persistence_ldap_mapping(persistence_type, ldap_mapping)
if persistence_type == "hybrid":
validate_persistence_hybrid_mapping()

if persistence_type == "sql":
sql_dialect = os.environ.get("CN_SQL_DB_DIALECT", "mysql")
validate_persistence_sql_dialect(sql_dialect)

manager = get_manager()
deps = ["config", "secret"]

if persistence_type == "hybrid":
deps += ["ldap", "couchbase"]
else:
deps.append(persistence_type)

wait_for(manager, deps)
wait_for_persistence(manager)


if __name__ == "__main__":
Expand Down
2 changes: 1 addition & 1 deletion docker-jans-certmanager/Dockerfile
Expand Up @@ -104,7 +104,7 @@ ENV CN_SECRET_ADAPTER=vault \
# ===============

ENV CN_PERSISTENCE_TYPE=ldap \
CN_PERSISTENCE_LDAP_MAPPING=default \
CN_HYBRID_MAPPING="{}" \
CN_LDAP_URL=localhost:1636 \
CN_LDAP_USE_SSL=true \
CN_COUCHBASE_URL=localhost \
Expand Down
44 changes: 38 additions & 6 deletions docker-jans-certmanager/README.md
Expand Up @@ -47,13 +47,13 @@ The following environment variables are supported by the container:
- `CN_SECRET_GOOGLE_SECRET_NAME_PREFIX`: Prefix for Google Secret Manager name (default to `jans`).
- `CN_SECRET_GOOGLE_SECRET_MANAGER_PASSPHRASE`: Passphrase for Google Secret Manager (default to `secret`).
- `CN_PERSISTENCE_TYPE`: Persistence backend being used (one of `ldap`, `couchbase`, or `hybrid`; default to `ldap`).
- `CN_PERSISTENCE_LDAP_MAPPING`: Specify data that should be saved in LDAP (one of `default`, `user`, `cache`, `site`, or `token`; default to `default`). Note this environment only takes effect when `CN_PERSISTENCE_TYPE` is set to `hybrid`.
- `CN_LDAP_URL`: Address and port of LDAP server (default to `localhost:1636`); required if `CN_PERSISTENCE_TYPE` is set to `ldap` or `hybrid`.
- `CN_HYBRID_MAPPING`: Specify data mapping for each persistence (default to `"{}"`). Note this environment only takes effect when `CN_PERSISTENCE_TYPE` is set to `hybrid`. See [hybrid mapping](#hybrid-mapping) section for details.
- `CN_LDAP_URL`: Address and port of LDAP server (default to `localhost:1636`).
- `CN_LDAP_USE_SSL`: Whether to use SSL connection to LDAP server (default to `true`).
- `CN_COUCHBASE_URL`: Address of Couchbase server (default to `localhost`); required if `CN_PERSISTENCE_TYPE` is set to `couchbase` or `hybrid`.
- `CN_COUCHBASE_USER`: Username of Couchbase server (default to `admin`); required if `CN_PERSISTENCE_TYPE` is set to `couchbase` or `hybrid`.
- `CN_COUCHBASE_CERT_FILE`: Couchbase root certificate location (default to `/etc/certs/couchbase.crt`); required if `CN_PERSISTENCE_TYPE` is set to `couchbase` or `hybrid`.
- `CN_COUCHBASE_PASSWORD_FILE`: Path to file contains Couchbase password (default to `/etc/jans/conf/couchbase_password`); required if `CN_PERSISTENCE_TYPE` is set to `couchbase` or `hybrid`.
- `CN_COUCHBASE_URL`: Address of Couchbase server (default to `localhost`).
- `CN_COUCHBASE_USER`: Username of Couchbase server (default to `admin`).
- `CN_COUCHBASE_CERT_FILE`: Couchbase root certificate location (default to `/etc/certs/couchbase.crt`).
- `CN_COUCHBASE_PASSWORD_FILE`: Path to file contains Couchbase password (default to `/etc/jans/conf/couchbase_password`).
- `CN_COUCHBASE_CONN_TIMEOUT`: Connect timeout used when a bucket is opened (default to `10000` milliseconds).
- `CN_COUCHBASE_CONN_MAX_WAIT`: Maximum time to wait before retrying connection (default to `20000` milliseconds).
- `CN_COUCHBASE_SCAN_CONSISTENCY`: Default scan consistency; one of `not_bounded`, `request_plus`, or `statement_plus` (default to `not_bounded`).
Expand Down Expand Up @@ -243,3 +243,35 @@ spec:
args: ["patch", "auth", "--opts", "interval:48"]
restartPolicy: Never
```

### Hybrid mapping

As per v1.0.1, hybrid persistence supports all available persistence types. To configure hybrid persistence and its data mapping, follow steps below:

1. Set `CN_PERSISTENCE_TYPE` environment variable to `hybrid`

1. Set `CN_HYBRID_MAPPING` with the following format:

```
{
"default": "<couchbase|ldap|spanner|sql>",
"user": "<couchbase|ldap|spanner|sql>",
"site": "<couchbase|ldap|spanner|sql>",
"cache": "<couchbase|ldap|spanner|sql>",
"token": "<couchbase|ldap|spanner|sql>",
"session": "<couchbase|ldap|spanner|sql>",
}
```

Example:

```
{
"default": "sql",
"user": "spanner",
"site": "ldap",
"cache": "sql",
"token": "couchbase",
"session": "spanner",
}
```
2 changes: 1 addition & 1 deletion docker-jans-certmanager/requirements.txt
Expand Up @@ -2,4 +2,4 @@
grpcio==1.41.0
click==6.7
libcst<0.4
git+https://github.com/JanssenProject/jans@89859286d69e7de7885bd9da9f50720c8371e797#egg=jans-pycloudlib&subdirectory=jans-pycloudlib
git+https://github.com/JanssenProject/jans@a0b7eac21ab3e405ad60e913f966476c34420c62#egg=jans-pycloudlib&subdirectory=jans-pycloudlib
18 changes: 5 additions & 13 deletions docker-jans-certmanager/scripts/auth_handler.py
Expand Up @@ -10,6 +10,7 @@
from jans.pycloudlib.persistence.ldap import LdapClient
from jans.pycloudlib.persistence.sql import SqlClient
from jans.pycloudlib.persistence.spanner import SpannerClient
from jans.pycloudlib.persistence.utils import PersistenceMapper
from jans.pycloudlib.utils import encode_text
from jans.pycloudlib.utils import exec_cmd
from jans.pycloudlib.utils import generate_base64_contents
Expand Down Expand Up @@ -113,7 +114,7 @@ def __init__(self, manager):
def get_auth_config(self):
bucket = os.environ.get("CN_COUCHBASE_BUCKET_PREFIX", "jans")
req = self.client.exec_query(
"SELECT jansRevision, jansConfDyn, jansConfWebKeys "
"SELECT jansRevision, jansConfDyn, jansConfWebKeys " # nosec: B608
f"FROM `{bucket}` "
"USE KEYS 'configuration_jans-auth'",
)
Expand Down Expand Up @@ -187,20 +188,11 @@ class AuthHandler(BaseHandler):
def __init__(self, manager, dry_run, **opts):
super().__init__(manager, dry_run, **opts)

persistence_type = os.environ.get("CN_PERSISTENCE_TYPE", "ldap")
ldap_mapping = os.environ.get("CN_PERSISTENCE_LDAP_MAPPING", "default")

if persistence_type in ("ldap", "couchbase", "sql", "spanner"):
backend_type = persistence_type
else:
# persistence_type is hybrid
if ldap_mapping == "default":
backend_type = "ldap"
else:
backend_type = "couchbase"

# resolve backend
mapper = PersistenceMapper()
backend_type = mapper.mapping["default"]
self.backend = _backend_classes[backend_type](manager)

self.rotation_interval = opts.get("interval", 48)
self.push_keys = as_boolean(opts.get("push-to-container", True))
self.key_strategy = opts.get("key-strategy", "OLDER")
Expand Down
2 changes: 1 addition & 1 deletion docker-jans-client-api/Dockerfile
Expand Up @@ -98,7 +98,7 @@ ENV CN_SECRET_ADAPTER=vault \
# ===============

ENV CN_PERSISTENCE_TYPE=ldap \
CN_PERSISTENCE_LDAP_MAPPING=default \
CN_HYBRID_MAPPING="{}" \
CN_LDAP_URL=localhost:1636 \
CN_LDAP_USE_SSL=true \
CN_COUCHBASE_URL=localhost \
Expand Down
43 changes: 37 additions & 6 deletions docker-jans-client-api/README.md
Expand Up @@ -46,13 +46,13 @@ The following environment variables are supported by the container:
- `CN_WAIT_SLEEP_DURATION`: Delay between startup "health checks" (default to `10` seconds).
- `CN_MAX_RAM_PERCENTAGE`: Value passed to Java option `-XX:MaxRAMPercentage`.
- `CN_PERSISTENCE_TYPE`: Persistence backend being used (one of `ldap`, `couchbase`, or `hybrid`; default to `ldap`).
- `CN_PERSISTENCE_LDAP_MAPPING`: Specify data that should be saved in LDAP (one of `default`, `user`, `cache`, `site`, or `token`; default to `default`). Note this environment only takes effect when `CN_PERSISTENCE_TYPE` is set to `hybrid`.
- `CN_LDAP_URL`: Address and port of LDAP server (default to `localhost:1636`); required if `CN_PERSISTENCE_TYPE` is set to `ldap` or `hybrid`.
- `CN_HYBRID_MAPPING`: Specify data mapping for each persistence (default to `"{}"`). Note this environment only takes effect when `CN_PERSISTENCE_TYPE` is set to `hybrid`. See [hybrid mapping](#hybrid-mapping) section for details.
- `CN_LDAP_URL`: Address and port of LDAP server (default to `localhost:1636`).
- `CN_LDAP_USE_SSL`: Whether to use SSL connection to LDAP server (default to `true`).
- `CN_COUCHBASE_URL`: Address of Couchbase server (default to `localhost`); required if `CN_PERSISTENCE_TYPE` is set to `couchbase` or `hybrid`.
- `CN_COUCHBASE_USER`: Username of Couchbase server (default to `admin`); required if `CN_PERSISTENCE_TYPE` is set to `couchbase` or `hybrid`.
- `CN_COUCHBASE_CERT_FILE`: Couchbase root certificate location (default to `/etc/certs/couchbase.crt`); required if `CN_PERSISTENCE_TYPE` is set to `couchbase` or `hybrid`.
- `CN_COUCHBASE_PASSWORD_FILE`: Path to file contains Couchbase password (default to `/etc/jans/conf/couchbase_password`); required if `CN_PERSISTENCE_TYPE` is set to `couchbase` or `hybrid`.
- `CN_COUCHBASE_URL`: Address of Couchbase server (default to `localhost`).
- `CN_COUCHBASE_USER`: Username of Couchbase server (default to `admin`).
- `CN_COUCHBASE_CERT_FILE`: Couchbase root certificate location (default to `/etc/certs/couchbase.crt`).
- `CN_COUCHBASE_PASSWORD_FILE`: Path to file contains Couchbase password (default to `/etc/jans/conf/couchbase_password`).
- `CN_COUCHBASE_CONN_TIMEOUT`: Connect timeout used when a bucket is opened (default to `10000` milliseconds).
- `CN_COUCHBASE_CONN_MAX_WAIT`: Maximum time to wait before retrying connection (default to `20000` milliseconds).
- `CN_COUCHBASE_SCAN_CONSISTENCY`: Default scan consistency; one of `not_bounded`, `request_plus`, or `statement_plus` (default to `not_bounded`).
Expand Down Expand Up @@ -95,3 +95,34 @@ The following key-value pairs are the defaults:
}
```

### Hybrid mapping

As per v1.0.1, hybrid persistence supports all available persistence types. To configure hybrid persistence and its data mapping, follow steps below:

1. Set `CN_PERSISTENCE_TYPE` environment variable to `hybrid`

1. Set `CN_HYBRID_MAPPING` with the following format:

```
{
"default": "<couchbase|ldap|spanner|sql>",
"user": "<couchbase|ldap|spanner|sql>",
"site": "<couchbase|ldap|spanner|sql>",
"cache": "<couchbase|ldap|spanner|sql>",
"token": "<couchbase|ldap|spanner|sql>",
"session": "<couchbase|ldap|spanner|sql>",
}
```

Example:

```
{
"default": "sql",
"user": "spanner",
"site": "ldap",
"cache": "sql",
"token": "couchbase",
"session": "spanner",
}
```
2 changes: 1 addition & 1 deletion docker-jans-client-api/requirements.txt
Expand Up @@ -2,4 +2,4 @@
grpcio==1.41.0
ruamel.yaml==0.16.10
libcst<0.4
git+https://github.com/JanssenProject/jans@89859286d69e7de7885bd9da9f50720c8371e797#egg=jans-pycloudlib&subdirectory=jans-pycloudlib
git+https://github.com/JanssenProject/jans@a0b7eac21ab3e405ad60e913f966476c34420c62#egg=jans-pycloudlib&subdirectory=jans-pycloudlib

0 comments on commit a77ab60

Please sign in to comment.