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

feature(sso): saml based sso using microsoft entra id #215

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
14 changes: 14 additions & 0 deletions llmstack/server/adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,17 @@ def populate_user(self, request, sociallogin, data):
user.email = user.username

return user

def pre_social_login(self, request, sociallogin):
if sociallogin.is_existing:
return

user = sociallogin.user

if not user.username:
user.username = user.email

if not user.email:
user.email = user.username

sociallogin.connect(request, user)
74 changes: 74 additions & 0 deletions llmstack/server/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,80 @@
},
}

ENABLE_SAML_SOCIALACCOUNT = os.getenv("ENABLE_SAML_SOCIALACCOUNT", "False") == "True"
if ENABLE_SAML_SOCIALACCOUNT:
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")

if "allauth.socialaccount.providers.saml" not in INSTALLED_APPS:
INSTALLED_APPS.append("allauth.socialaccount.providers.saml")

"""
SAMPLE CONFIG from .bashrc/.zshrc. x509cert is configure in a separate env variable

```bash
export SAML_APP_NAME="Test Org Inc"
export SAML_APP_CLIENT_ID="test-org-inc"
export SAML_APP_TENANT_ID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
export SAML_APP_CONFIG=$(cat <<EOF
{
"name": "$SAML_APP_NAME",
"provider_id": "https://login.microsoftonline.com/$SAML_APP_TENANT_ID/",
"client_id": "$SAML_APP_CLIENT_ID",
"settings_attribute_mapping": {
"uid": "http://schemas.microsoft.com/identity/claims/objectidentifier",
"email": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
"first_name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname",
"last_name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"
},
"settings_idp": {
"entity_id": "https://sts.windows.net/$SAML_APP_TENANT_ID/",
"sso_url": "https://login.microsoftonline.com/$SAML_APP_TENANT_ID/saml2",
"slo_url": "https://login.microsoftonline.com/$SAML_APP_TENANT_ID/saml2"
},
"settings_advanced": {
"strict": false,
"authn_requests_signed": false,
"logout_request_signed": false,
"logout_response_signed": false,
"requested_authn_context": false,
"sign_metadata": false,
"want_assertion_encrypted": false,
"want_assertion_signed": false,
"want_messages_signed": false
}
}
EOF
)

export SAML_APP_CERTIFICATE="
-----BEGIN CERTIFICATE-----
MIIC8...
-----END CERTIFICATE-----
"
```
"""
# Microsoft Entra ID SAML Configuration
SAML_APP_CONFIG = json.loads(os.getenv("SAML_APP_CONFIG") or "{}", strict=False)
SAML_APP_X509_CERTIFICATE = os.getenv("SAML_APP_CERTIFICATE", "")

SAML_APP_SETTINGS_IDP = SAML_APP_CONFIG["settings_idp"]
SAML_APP_SETTINGS_IDP["x509cert"] = SAML_APP_X509_CERTIFICATE

SAML_APP = {
"name": SAML_APP_CONFIG["name"],
"provider_id": SAML_APP_CONFIG["provider_id"],
"client_id": SAML_APP_CONFIG["client_id"],
"settings": {
Balu-Varanasi marked this conversation as resolved.
Show resolved Hide resolved
"attribute_mapping": SAML_APP_CONFIG["settings_attribute_mapping"],
"idp": SAML_APP_SETTINGS_IDP,
"advanced": SAML_APP_CONFIG["settings_advanced"],
},
}

SOCIALACCOUNT_PROVIDERS["saml"] = {
"APPS": [SAML_APP],
}

EVENT_TOPIC_MAPPING = {
"app.run.finished": [
{
Expand Down
64 changes: 62 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ optional = false

[tool.poetry.group.server.dependencies]
django = {version = "5.0", python = ">=3.10,<3.12" }
django-allauth = {version = "^0.61.1", allow-prereleases = true}
django-allauth = {version = "^0.61.1", allow-prereleases = true, extras = ["saml"]}
django-environ = {version = "^0.10.0", allow-prereleases = true}
django-picklefield = {version = "^3.1", allow-prereleases = true}
django-redis = {version = "^5.2.0", allow-prereleases = true}
Expand Down
Loading