Compare commits
No commits in common. "74280d609367065f837e8a888559bad82b0b8932" and "283568245524781d3700b8e0f2675d09365c5c1e" have entirely different histories.
74280d6093
...
2835682455
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,2 @@
|
|||||||
*.pyc
|
*.pyc
|
||||||
.env
|
|
||||||
/__pycache__/
|
/__pycache__/
|
||||||
|
27
README.md
27
README.md
@ -27,7 +27,6 @@ No Masters edition of Keycloak.
|
|||||||
- They are valid for 30 days by default (configurable via `INVITE_TIME_LIMIT`)
|
- They are valid for 30 days by default (configurable via `INVITE_TIME_LIMIT`)
|
||||||
- Anyone with an invite link can create an account on the Keycloak, so don't share publicly!
|
- Anyone with an invite link can create an account on the Keycloak, so don't share publicly!
|
||||||
- There is no access granularity on the account creation implemented yet, so the accounts are "global"
|
- There is no access granularity on the account creation implemented yet, so the accounts are "global"
|
||||||
- **New**: it is possible to only allow "admins" to log in, see [feature flags](#feature-flags)
|
|
||||||
- Once the user fills in their name, email, password they will receive an email verification mail
|
- Once the user fills in their name, email, password they will receive an email verification mail
|
||||||
|
|
||||||
If you want a feature implemented, please open an issue to discuss.
|
If you want a feature implemented, please open an issue to discuss.
|
||||||
@ -61,32 +60,6 @@ your technology stack.
|
|||||||
- Log in with your usual login details
|
- Log in with your usual login details
|
||||||
- Follow the instructions on the web page to perform administrative actions
|
- Follow the instructions on the web page to perform administrative actions
|
||||||
|
|
||||||
## Feature Flags
|
|
||||||
|
|
||||||
### Only admins can log in
|
|
||||||
|
|
||||||
#### Keycloak
|
|
||||||
|
|
||||||
- Create a new group under `Groups` called `Administrators` (case sensistive!)
|
|
||||||
- Create a new scope under `Client scopes`
|
|
||||||
- Name: `groups`
|
|
||||||
- Type: `Optional`
|
|
||||||
- Include in token scope: `yes`
|
|
||||||
- Under the `Mappers` tab of this client scope, choose `Add mapper`
|
|
||||||
- Mapper type/Name: `Groups Membership`
|
|
||||||
- Token claim name: `groups`
|
|
||||||
- Add to ID token: `yes`
|
|
||||||
- Add to access token: `yes`
|
|
||||||
- Add to userinfo: `yes`
|
|
||||||
- Add this client scope to your `admin-cli` client as `Optional`
|
|
||||||
- Add a test user to this group under `Users`
|
|
||||||
|
|
||||||
#### Keycloak Community Portal
|
|
||||||
|
|
||||||
- Set `FEATURE_FLAG_ADMINS_ONLY=True` in your `.env`
|
|
||||||
- You may want to customise `KEYCLOAK_GROUPS_KEY` / `KEYCLOAK_ADMINS_GROUP` if
|
|
||||||
you changed the value of `groups` / `Administrators` above
|
|
||||||
|
|
||||||
## Hacking
|
## Hacking
|
||||||
|
|
||||||
It's a [FastAPI](https://fastapi.tiangolo.com/) application (if you know
|
It's a [FastAPI](https://fastapi.tiangolo.com/) application (if you know
|
||||||
|
@ -12,9 +12,7 @@ KEYCLOAK_CLIENT_ID = environ.get("KEYCLOAK_CLIENT_ID")
|
|||||||
KEYCLOAK_CLIENT_SECRET = environ.get("KEYCLOAK_CLIENT_SECRET")
|
KEYCLOAK_CLIENT_SECRET = environ.get("KEYCLOAK_CLIENT_SECRET")
|
||||||
KEYCLOAK_DOMAIN = environ.get("KEYCLOAK_DOMAIN")
|
KEYCLOAK_DOMAIN = environ.get("KEYCLOAK_DOMAIN")
|
||||||
KEYCLOAK_REALM = environ.get("KEYCLOAK_REALM")
|
KEYCLOAK_REALM = environ.get("KEYCLOAK_REALM")
|
||||||
KEYCLOAK_SCOPES = environ.get("KEYCLOAK_SCOPES", "openid profile email groups")
|
KEYCLOAK_SCOPES = environ.get("KEYCLOAK_SCOPES", "openid profile email")
|
||||||
KEYCLOAK_GROUPS_KEY = environ.get("KEYCLOAK_GROUPS_KEY", "groups")
|
|
||||||
KEYCLOAK_ADMINS_GROUP = environ.get("KEYCLOAK_ADMINS_GROUP", "Administrators")
|
|
||||||
KEYCLOAK_BASE_URL = f"https://{KEYCLOAK_DOMAIN}/realms/{KEYCLOAK_REALM}/protocol/openid-connect" # noqa
|
KEYCLOAK_BASE_URL = f"https://{KEYCLOAK_DOMAIN}/realms/{KEYCLOAK_REALM}/protocol/openid-connect" # noqa
|
||||||
|
|
||||||
# Redis connection details, our main storage
|
# Redis connection details, our main storage
|
||||||
@ -41,15 +39,5 @@ elif LOG_LEVEL == "debug":
|
|||||||
else:
|
else:
|
||||||
APP_LOG_LEVEL = logging.INFO
|
APP_LOG_LEVEL = logging.INFO
|
||||||
|
|
||||||
|
|
||||||
def to_bool(env_var):
|
|
||||||
"""Parse a bool from the environment."""
|
|
||||||
return environ.get(env_var, "False").lower() in ("true", "1", "t")
|
|
||||||
|
|
||||||
|
|
||||||
# Automatically log folks in or show the default log in page?
|
# Automatically log folks in or show the default log in page?
|
||||||
AUTOMATICALLY_LOG_IN = to_bool("AUTOMATICALLY_LOG_IN")
|
AUTOMATICALLY_LOG_IN = environ.get("AUTOMATICALLY_LOG_IN", False)
|
||||||
|
|
||||||
# Feature flags
|
|
||||||
# Only admins can log in to the interface
|
|
||||||
FEATURE_FLAG_ADMINS_ONLY = to_bool("FEATURE_FLAG_ADMINS_ONLY")
|
|
||||||
|
@ -15,26 +15,7 @@ router = APIRouter()
|
|||||||
async def home(
|
async def home(
|
||||||
request: Request, user=Depends(get_user), invites=Depends(get_invites)
|
request: Request, user=Depends(get_user), invites=Depends(get_invites)
|
||||||
):
|
):
|
||||||
from keycloak_collective_portal.config import (
|
|
||||||
FEATURE_FLAG_ADMINS_ONLY,
|
|
||||||
KEYCLOAK_ADMINS_GROUP,
|
|
||||||
KEYCLOAK_GROUPS_KEY,
|
|
||||||
)
|
|
||||||
|
|
||||||
context = {"request": request, "user": user, "invites": invites}
|
context = {"request": request, "user": user, "invites": invites}
|
||||||
|
|
||||||
if FEATURE_FLAG_ADMINS_ONLY:
|
|
||||||
context["message"] = "only admins can access this service"
|
|
||||||
if KEYCLOAK_GROUPS_KEY not in user:
|
|
||||||
return request.app.state.templates.TemplateResponse(
|
|
||||||
"invalid.html", context=context
|
|
||||||
)
|
|
||||||
|
|
||||||
if KEYCLOAK_ADMINS_GROUP not in user[KEYCLOAK_GROUPS_KEY]:
|
|
||||||
return request.app.state.templates.TemplateResponse(
|
|
||||||
"invalid.html", context=context
|
|
||||||
)
|
|
||||||
|
|
||||||
return request.app.state.templates.TemplateResponse(
|
return request.app.state.templates.TemplateResponse(
|
||||||
"admin.html", context=context
|
"admin.html", context=context
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user