From 2c3749820e1f5f79ecdad74e8f97eae275c944c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=83=E7=9F=B3?= Date: Sun, 15 Sep 2024 23:00:50 +0800 Subject: [PATCH] feat: add application.UseEmailAsSamlNameId field for SAML (#3203) * feat: Add option to use email as SAML NameID based on application config - Updated NewSamlResponse11 to accept an application parameter. - Conditionally set SAML NameIdentifier to user's email or username based on application.UseEmailAsNameId. * refactor: Update GetValidationBySaml to pass application to NewSamlResponse11 - Modified GetValidationBySaml function to include application parameter in NewSamlResponse11 call. * feat: Rename field and update logic for using Email as SAML NameID - Renamed the `UseEmailAsNameId` field to `UseEmailAsSamlNameId` in the `Application` struct. - Updated `NewSamlResponse` and `NewSamlResponse11` functions to use `UseEmailAsSamlNameId` for setting the NameID value. - Modified `ApplicationEditPage.js` to reflect the field name change and update the corresponding logic. --- object/application.go | 1 + object/saml_idp.go | 20 ++++++++++++++++---- object/token_cas.go | 2 +- web/src/ApplicationEditPage.js | 10 ++++++++++ 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/object/application.go b/object/application.go index 11caf725..a75fc987 100644 --- a/object/application.go +++ b/object/application.go @@ -78,6 +78,7 @@ type Application struct { EnableSamlCompress bool `json:"enableSamlCompress"` EnableSamlC14n10 bool `json:"enableSamlC14n10"` EnableSamlPostBinding bool `json:"enableSamlPostBinding"` + UseEmailAsSamlNameId bool `json:"useEmailAsSamlNameId"` EnableWebAuthn bool `json:"enableWebAuthn"` EnableLinkWithEmail bool `json:"enableLinkWithEmail"` OrgChoiceMode string `json:"orgChoiceMode"` diff --git a/object/saml_idp.go b/object/saml_idp.go index 3856e816..53252407 100644 --- a/object/saml_idp.go +++ b/object/saml_idp.go @@ -65,7 +65,11 @@ func NewSamlResponse(application *Application, user *User, host string, certific assertion.CreateAttr("IssueInstant", now) assertion.CreateElement("saml:Issuer").SetText(host) subject := assertion.CreateElement("saml:Subject") - subject.CreateElement("saml:NameID").SetText(user.Name) + nameIDValue := user.Name + if application.UseEmailAsSamlNameId { + nameIDValue = user.Email + } + subject.CreateElement("saml:NameID").SetText(nameIDValue) subjectConfirmation := subject.CreateElement("saml:SubjectConfirmation") subjectConfirmation.CreateAttr("Method", "urn:oasis:names:tc:SAML:2.0:cm:bearer") subjectConfirmationData := subjectConfirmation.CreateElement("saml:SubjectConfirmationData") @@ -386,7 +390,7 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h } // NewSamlResponse11 return a saml1.1 response(not 2.0) -func NewSamlResponse11(user *User, requestID string, host string) (*etree.Element, error) { +func NewSamlResponse11(application *Application, user *User, requestID string, host string) (*etree.Element, error) { samlResponse := &etree.Element{ Space: "samlp", Tag: "Response", @@ -430,7 +434,11 @@ func NewSamlResponse11(user *User, requestID string, host string) (*etree.Elemen // nameIdentifier inside subject nameIdentifier := subject.CreateElement("saml:NameIdentifier") // nameIdentifier.CreateAttr("Format", "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress") - nameIdentifier.SetText(user.Name) + if application.UseEmailAsSamlNameId { + nameIdentifier.SetText(user.Email) + } else { + nameIdentifier.SetText(user.Name) + } // subjectConfirmation inside subject subjectConfirmation := subject.CreateElement("saml:SubjectConfirmation") @@ -439,7 +447,11 @@ func NewSamlResponse11(user *User, requestID string, host string) (*etree.Elemen attributeStatement := assertion.CreateElement("saml:AttributeStatement") subjectInAttribute := attributeStatement.CreateElement("saml:Subject") nameIdentifierInAttribute := subjectInAttribute.CreateElement("saml:NameIdentifier") - nameIdentifierInAttribute.SetText(user.Name) + if application.UseEmailAsSamlNameId { + nameIdentifierInAttribute.SetText(user.Email) + } else { + nameIdentifierInAttribute.SetText(user.Name) + } subjectConfirmationInAttribute := subjectInAttribute.CreateElement("saml:SubjectConfirmation") subjectConfirmationInAttribute.CreateElement("saml:ConfirmationMethod").SetText("urn:oasis:names:tc:SAML:1.0:cm:artifact") diff --git a/object/token_cas.go b/object/token_cas.go index 3cd4de5c..2334e371 100644 --- a/object/token_cas.go +++ b/object/token_cas.go @@ -281,7 +281,7 @@ func GetValidationBySaml(samlRequest string, host string) (string, string, error return "", "", fmt.Errorf("the application for user %s is not found", userId) } - samlResponse, err := NewSamlResponse11(user, request.RequestID, host) + samlResponse, err := NewSamlResponse11(application, user, request.RequestID, host) if err != nil { return "", "", err } diff --git a/web/src/ApplicationEditPage.js b/web/src/ApplicationEditPage.js index 8bba3d37..4a510338 100644 --- a/web/src/ApplicationEditPage.js +++ b/web/src/ApplicationEditPage.js @@ -703,6 +703,16 @@ class ApplicationEditPage extends React.Component { }} /> + + + {Setting.getLabel(i18next.t("application:Use Email as NameID"), i18next.t("application:Use Email as NameID - Tooltip"))} : + + + { + this.updateApplicationField("useEmailAsSamlNameId", checked); + }} /> + + {Setting.getLabel(i18next.t("application:Enable SAML POST binding"), i18next.t("application:Enable SAML POST binding - Tooltip"))} :