mirror of
https://github.com/mediacms-io/mediacms.git
synced 2026-06-06 17:13:02 -04:00
feat: configure SP certificate and private key via SAMLConfiguration (#1531)
This commit is contained in:
+1
-1
@@ -1 +1 @@
|
||||
VERSION = "8.1.2"
|
||||
VERSION = "8.2.0"
|
||||
|
||||
@@ -947,6 +947,8 @@ Select the SAML Configurations tab, create a new one and set:
|
||||
3. **SSO URL**:
|
||||
4. **SLO URL**:
|
||||
5. **SP Metadata URL**: The metadata URL that the IDP will utilize. This can be https://{portal}/saml/metadata and is autogenerated by MediaCMS
|
||||
6. **SP Certificate** (optional): SP x509 certificate (PEM). Enables encrypted/signed SAML communication. If set, the SP Private Key must also be provided, and the certificate is published in the SP metadata so the IDP can encrypt assertions to MediaCMS.
|
||||
7. **SP Private Key** (optional): SP private key (PEM). Used to sign AuthnRequests/LogoutRequests and to decrypt assertions encrypted by the IDP. Required if SP Certificate is provided.
|
||||
|
||||
- Step 3: Set other Options
|
||||
1. **Email Settings**:
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ class SAMLConfigurationAdmin(admin.ModelAdmin):
|
||||
search_fields = ['social_app__name', 'idp_id', 'sp_metadata_url']
|
||||
|
||||
fieldsets = [
|
||||
('Provider Settings', {'fields': ['social_app', 'idp_id', 'idp_cert']}),
|
||||
('Provider Settings', {'fields': ['social_app', 'idp_id', 'idp_cert', 'sp_cert', 'sp_private_key']}),
|
||||
('URLs', {'fields': ['sso_url', 'slo_url', 'sp_metadata_url']}),
|
||||
('Group Management', {'fields': ['remove_from_groups', 'save_saml_response_logs']}),
|
||||
('Attribute Mapping', {'fields': ['uid', 'name', 'email', 'groups', 'first_name', 'last_name', 'user_logo', 'role']}),
|
||||
|
||||
@@ -53,16 +53,12 @@ def build_sp_config(request, provider_config, org):
|
||||
"binding": OneLogin_Saml2_Constants.BINDING_HTTP_REDIRECT,
|
||||
},
|
||||
}
|
||||
if _sp_config.get("x509cert"):
|
||||
sp_config["x509cert"] = _sp_config["x509cert"]
|
||||
if _sp_config.get("private_key"):
|
||||
sp_config["privateKey"] = _sp_config["private_key"]
|
||||
|
||||
avd = provider_config.get("advanced", {})
|
||||
if avd.get("x509cert") is not None:
|
||||
sp_config["x509cert"] = avd["x509cert"]
|
||||
|
||||
if avd.get("x509cert_new"):
|
||||
sp_config["x509certNew"] = avd["x509cert_new"]
|
||||
|
||||
if avd.get("private_key") is not None:
|
||||
sp_config["privateKey"] = avd["private_key"]
|
||||
|
||||
if avd.get("name_id_format") is not None:
|
||||
sp_config["NameIDFormat"] = avd["name_id_format"]
|
||||
|
||||
|
||||
@@ -154,7 +154,9 @@ sls = SLSView.as_view()
|
||||
class MetadataView(SAMLViewMixin, View):
|
||||
def dispatch(self, request, organization_slug):
|
||||
provider = self.get_provider(organization_slug)
|
||||
config = build_saml_config(self.request, provider.app.settings, organization_slug)
|
||||
custom_configuration = provider.app.saml_configurations.first()
|
||||
provider_config = custom_configuration.saml_provider_settings if custom_configuration else provider.app.settings
|
||||
config = build_saml_config(self.request, provider_config, organization_slug)
|
||||
saml_settings = OneLogin_Saml2_Settings(settings=config, sp_validation_only=True)
|
||||
metadata = saml_settings.get_sp_metadata()
|
||||
errors = saml_settings.validate_metadata(metadata)
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 5.2.6 on 2026-05-31 12:40
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('saml_auth', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='samlconfiguration',
|
||||
name='sp_cert',
|
||||
field=models.TextField(blank=True, help_text='SP x509cert (PEM). Optional; required if SP private key is set.', null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='samlconfiguration',
|
||||
name='sp_private_key',
|
||||
field=models.TextField(blank=True, help_text='SP private key (PEM). Optional; required if SP certificate is set.', null=True),
|
||||
),
|
||||
]
|
||||
@@ -14,6 +14,8 @@ class SAMLConfiguration(models.Model):
|
||||
|
||||
# Certificates
|
||||
idp_cert = models.TextField(help_text='x509cert')
|
||||
sp_cert = models.TextField(blank=True, null=True, help_text='SP x509cert (PEM). Optional; required if SP private key is set.')
|
||||
sp_private_key = models.TextField(blank=True, null=True, help_text='SP private key (PEM). Optional; required if SP certificate is set.')
|
||||
|
||||
# Attribute Mapping Fields
|
||||
uid = models.CharField(max_length=100, help_text='eg eduPersonPrincipalName')
|
||||
@@ -49,6 +51,11 @@ class SAMLConfiguration(models.Model):
|
||||
if existing_conf.exists():
|
||||
raise ValidationError({'social_app': 'Cannot create configuration for the same social app because one configuration already exists.'})
|
||||
|
||||
if self.sp_cert and not self.sp_private_key:
|
||||
raise ValidationError({'sp_private_key': 'Required when SP certificate is provided.'})
|
||||
if self.sp_private_key and not self.sp_cert:
|
||||
raise ValidationError({'sp_cert': 'Required when SP private key is provided.'})
|
||||
|
||||
super().clean()
|
||||
|
||||
@property
|
||||
@@ -56,6 +63,10 @@ class SAMLConfiguration(models.Model):
|
||||
# provide settings in a way for Social App SAML provider
|
||||
provider_settings = {}
|
||||
provider_settings["sp"] = {"entity_id": self.sp_metadata_url}
|
||||
if self.sp_cert:
|
||||
provider_settings["sp"]["x509cert"] = self.sp_cert
|
||||
if self.sp_private_key:
|
||||
provider_settings["sp"]["private_key"] = self.sp_private_key
|
||||
provider_settings["idp"] = {"slo_url": self.slo_url, "sso_url": self.sso_url, "x509cert": self.idp_cert, "entity_id": self.idp_id}
|
||||
|
||||
provider_settings["attribute_mapping"] = {
|
||||
|
||||
Reference in New Issue
Block a user