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

Documentation, improvements, clean up #1966

Merged
merged 5 commits into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 49 additions & 10 deletions docs/content/usage/authentication.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,16 +354,55 @@ Notice: Reverse Proxy Auth doesn't support the API. You still need an access tok

### Configuring Gitea as a SAML 2.0 Service Provider

- Navigate to `Site Administration > Identity & Access > Authentication Sources`
- Click the `Add Authentication Source` button
- Select `SAML` as the authentication type and specify an authentication source name in `Authentication Name`.
- The `SAML NameID Format` dropdown specifies how Identity Provider (IdP) users are mapped to Gitea users. This option will be provider specific.
- The `[Insecure] Skip Assertion Signature Validation` option is not recommended and disables integrity verification of IdP SAML assertions.
- Either `Identity Provider Metadata URL` or `Identity Provider Metadata XML` must be specified.
- Specifically, `Identity Provider Metadata XML` should be the XML metadata returned by the IdP metadata endpoint. This may be omitted if the endpoint url is recorded in `Identity Provider Metadata URL`.
- You should generate an X.509-formatted certificate and DSA/RSA private key for signing SAML requests. These are specified in `Service Provider Certificate` and `Service Provider Private Key` respectively.
- The checkbox `Sign SAML Requests` should be enabled if a certificate and private key are provided.
- `Email Assertion Key` (email), `Name Assertion Key` (nickname), and `Username Assertion Key` (username) specify how IdP user attributes are mapped to Gitea user attributes. These will be provider specific (or configurable).
- Navigate to `Site Administration > Identity & Access > Authentication Sources`.
- Click the `Add Authentication Source` button.
- Select `SAML` as the authentication type.

#### Settings

- `Authentication Name` **(required)**

- The name of this authentication source (appears in the Gitea ACS and metadata URLs)

- `SAML NameID Format` **(required)**

- This specifies how Identity Provider (IdP) users are mapped to Gitea users. This option will be provider specific.

- `[Insecure] Skip Assertion Signature Validation` (optional)

- This option is not recommended and disables integrity verification of IdP SAML assertions.

- `Identity Provider Metadata URL` (optional if XML set)

- The URL of the IdP metadata endpoint.
- This field must be set if `Identity Provider Metadata XML` is left blank.

- `Identity Provider Metadata XML` (optional if URL set)

- The XML returned by the IdP metadata endpoint.
- This field must be set if `Identity Provider Metadata URL` is left blank.

- `Service Provider Certificate` (optional)

- X.509-formatted certificate (with `Service Provider Private Key`) used for signing SAML requests.
- A certificate will be generated if this field is left blank.

- `Service Provider Private Key` (optional)

- DSA/RSA private key (with `Service Provider Certificate`) used for signing SAML requests.
- A private key will be generated if this field is left blank.

- `Email Assertion Key` (optional)

- The SAML assertion key used for the IdP user's email (depends on provider configuration).

- `Name Assertion Key` (optional)

- The SAML assertion key used for the IdP user's nickname (depends on provider configuration).

- `Username Assertion Key` (optional)

- The SAML assertion key used for the IdP user's username (depends on provider configuration).

### Configuring a SAML 2.0 Identity Provider to use Gitea

Expand Down
5 changes: 4 additions & 1 deletion options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,9 @@ Content = Content
SSPISeparatorReplacement = Separator
SSPIDefaultLanguage = Default Language

SAMLMetadata = Either SAML Identity Provider metadata URL or XML
SAMLMetadataURL = SAML Identity Provider metadata URL is invalid

require_error = ` cannot be empty.`
alpha_dash_error = ` should contain only alphanumeric, dash ('-') and underscore ('_') characters.`
alpha_dash_dot_error = ` should contain only alphanumeric, dash ('-'), underscore ('_') and dot ('.') characters.`
Expand Down Expand Up @@ -2995,11 +2998,11 @@ auths.saml_identity_provider_metadata = Identity Provider Metadata XML
auths.saml_insecure_skip_assertion_signature_validation = [Insecure] Skip Assertion Signature Validation
auths.saml_service_provider_certificate = Service Provider Certificate
auths.saml_service_provider_private_key = Service Provider Private Key
auths.saml_sign_requests = Sign SAML Requests
auths.saml_identity_provider_email_assertion_key = Email Assertion Key
auths.saml_identity_provider_name_assertion_key = Name Assertion Key
auths.saml_identity_provider_username_assertion_key = Username Assertion Key
auths.tips = Tips
auths.tips.saml = Documentation can be found at https://docs.gitea.com/usage/authentication#saml
auths.tips.oauth2.general = OAuth2 Authentication
auths.tips.oauth2.general.tip = When registering a new OAuth2 authentication, the callback/redirect URL should be:
auths.tip.oauth2_provider = OAuth2 Provider
Expand Down
17 changes: 6 additions & 11 deletions routers/web/admin/auths.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,23 +249,18 @@ func parseSSPIConfig(ctx *context.Context, form forms.AuthenticationForm) (*sspi
}

func parseSAMLConfig(ctx *context.Context, form forms.AuthenticationForm) (*saml.Source, error) {
if util.IsEmptyString(form.ServiceProviderCertificate) {
ctx.Data["Err_SSPISeparatorReplacement"] = true
return nil, errors.New(ctx.Tr("form.require_error"))
}
if util.IsEmptyString(form.ServiceProviderPrivateKey) {
ctx.Data["Err_SSPISeparatorReplacement"] = true
return nil, errors.New(ctx.Tr("form.require_error"))
}
if util.IsEmptyString(form.IdentityProviderMetadata) && util.IsEmptyString(form.IdentityProviderMetadataURL) {
return nil, fmt.Errorf("Identity Provider Metadata needed (either raw XML or URL)")
return nil, errors.New(ctx.Tr("form.SAMLMetadata") + ctx.Tr("form.require_error"))
}

if !util.IsEmptyString(form.IdentityProviderMetadataURL) {
_, err := url.Parse(form.IdentityProviderMetadataURL)
if err != nil {
return nil, fmt.Errorf("Identity Provider Metadata URL is an invalid URL")
return nil, errors.New(ctx.Tr("form.SAMLMetadataURL"))
}
}

// check the integrity of the certificate and private key (autogenerated if these form fields are blank)
if !util.IsEmptyString(form.ServiceProviderCertificate) && !util.IsEmptyString(form.ServiceProviderPrivateKey) {
keyPair, err := tls.X509KeyPair([]byte(form.ServiceProviderCertificate), []byte(form.ServiceProviderPrivateKey))
if err != nil {
Expand All @@ -276,14 +271,14 @@ func parseSAMLConfig(ctx *context.Context, form forms.AuthenticationForm) (*saml
return nil, err
}
}

return &saml.Source{
IdentityProviderMetadata: form.IdentityProviderMetadata,
IdentityProviderMetadataURL: form.IdentityProviderMetadataURL,
InsecureSkipAssertionSignatureValidation: form.InsecureSkipAssertionSignatureValidation,
NameIDFormat: saml.NameIDFormat(form.NameIDFormat),
ServiceProviderCertificate: form.ServiceProviderCertificate,
ServiceProviderPrivateKey: form.ServiceProviderPrivateKey,
SignRequests: form.SignRequests,
EmailAssertionKey: form.EmailAssertionKey,
NameAssertionKey: form.NameAssertionKey,
UsernameAssertionKey: form.UsernameAssertionKey,
Expand Down
3 changes: 1 addition & 2 deletions services/auth/source/saml/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ type Source struct {
ServiceProviderIssuer string
// ServiceProviderPrivateKey description: The SAML Service Provider private key in PKCS#8 encoding (begins with "-----BEGIN PRIVATE KEY-----"). This private key is used to sign AuthnRequests and LogoutRequests. It corresponds to the Service Provider's certificate (`serviceProviderCertificate`). To escape the value into a JSON string, you may want to use a tool like https://json-escape-text.now.sh.
ServiceProviderPrivateKey string
// SignRequests description: Sign AuthnRequests and LogoutRequests sent to the Identity Provider using the Service Provider's private key (`serviceProviderPrivateKey`). It defaults to true if the `serviceProviderPrivateKey` and `serviceProviderCertificate` are set, and false otherwise.
SignRequests bool

CallbackURL string

Expand Down Expand Up @@ -134,6 +132,7 @@ func (source *Source) initSAMLSp() error {
SkipSignatureValidation: source.InsecureSkipAssertionSignatureValidation,
NameIdFormat: source.NameIDFormat.String(),
IDPCertificateStore: &certStore,
SignAuthnRequests: true,
SPKeyStore: keyStore,
ServiceProviderIssuer: setting.AppURL + "user/saml/" + url.PathEscape(source.authSource.Name) + "/metadata",
}
Expand Down
1 change: 0 additions & 1 deletion services/forms/auth_form.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ type AuthenticationForm struct {
InsecureSkipAssertionSignatureValidation bool
ServiceProviderCertificate string
ServiceProviderPrivateKey string
SignRequests bool
EmailAssertionKey string
NameAssertionKey string
UsernameAssertionKey string
Expand Down
28 changes: 12 additions & 16 deletions templates/admin/auth/edit.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@
{{if .Source.IsSAML}}
{{$cfg:=.Source.Cfg}}
<div class="inline required field">
<label>{{.locale.Tr "admin.auths.saml_nameidformat"}}</label>
<label>{{ctx.Locale.Tr "admin.auths.saml_nameidformat"}}</label>
<div class="ui selection type dropdown">
<input type="hidden" id="name_id_format" name="name_id_format" value="{{$cfg.NameIDFormat}}">
<div class="text">{{.CurrentNameIDFormat}}</div>
Expand All @@ -385,49 +385,42 @@
</div>

<div class="field">
<label for="identity_provider_metadata_url">{{.locale.Tr "admin.auths.saml_identity_provider_metadata_url"}}</label>
<label for="identity_provider_metadata_url">{{ctx.Locale.Tr "admin.auths.saml_identity_provider_metadata_url"}}</label>
<input id="identity_provider_metadata_url" name="identity_provider_metadata_url" value="{{$cfg.IdentityProviderMetadataURL}}">
</div>
<div class="field">
<label for="identity_provider_metadata">{{.locale.Tr "admin.auths.saml_identity_provider_metadata"}}</label>
<label for="identity_provider_metadata">{{ctx.Locale.Tr "admin.auths.saml_identity_provider_metadata"}}</label>
<textarea rows=2 id="identity_provider_metadata" name="identity_provider_metadata">{{$cfg.IdentityProviderMetadata}}</textarea>
</div>

<div class="inline field">
<div class="ui checkbox">
<label><strong>{{.locale.Tr "admin.auths.saml_insecure_skip_assertion_signature_validation"}}</strong></label>
<label><strong>{{ctx.Locale.Tr "admin.auths.saml_insecure_skip_assertion_signature_validation"}}</strong></label>
<input name="insecure_skip_assertion_signature_validation" type="checkbox" {{if $cfg.InsecureSkipAssertionSignatureValidation}}checked{{end}}>
</div>
</div>

<div class=" field">
<label for="service_provider_certificate">{{.locale.Tr "admin.auths.saml_service_provider_certificate"}}</label>
<label for="service_provider_certificate">{{ctx.Locale.Tr "admin.auths.saml_service_provider_certificate"}}</label>
<textarea rows=2 id="service_provider_certificate" name="service_provider_certificate">{{$cfg.ServiceProviderCertificate}}</textarea>
</div>
<div class=" field">
<label for="service_provider_private_key">{{.locale.Tr "admin.auths.saml_service_provider_private_key"}}</label>
<label for="service_provider_private_key">{{ctx.Locale.Tr "admin.auths.saml_service_provider_private_key"}}</label>
<textarea rows=2 id="service_provider_private_key" name="service_provider_private_key">{{$cfg.ServiceProviderPrivateKey}}</textarea>
</div>

<div class="inline field">
<div class="ui checkbox">
<label><strong>{{.locale.Tr "admin.auths.saml_sign_requests"}}</strong></label>
<input name="sign_requests" type="checkbox" {{if $cfg.SignRequests}}checked{{end}}>
</div>
</div>

<div class="field">
<label for="email_assertion_key">{{.locale.Tr "admin.auths.saml_identity_provider_email_assertion_key"}}</label>
<label for="email_assertion_key">{{ctx.Locale.Tr "admin.auths.saml_identity_provider_email_assertion_key"}}</label>
<input id="email_assertion_key" name="email_assertion_key" value="{{if not $cfg.EmailAssertionKey}}http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress{{else}}{{$cfg.EmailAssertionKey}}{{end}}">
</div>

<div class="field">
<label for="name_assertion_key">{{.locale.Tr "admin.auths.saml_identity_provider_name_assertion_key"}}</label>
<label for="name_assertion_key">{{ctx.Locale.Tr "admin.auths.saml_identity_provider_name_assertion_key"}}</label>
<input id="name_assertion_key" name="name_assertion_key" value="{{if not $cfg.NameAssertionKey}}http://schemas.xmlsoap.org/claims/CommonName{{else}}{{$cfg.NameAssertionKey}}{{end}}">
</div>

<div class="field">
<label for="username_assertion_key">{{.locale.Tr "admin.auths.saml_identity_provider_username_assertion_key"}}</label>
<label for="username_assertion_key">{{ctx.Locale.Tr "admin.auths.saml_identity_provider_username_assertion_key"}}</label>
<input id="username_assertion_key" name="username_assertion_key" value="{{if not $cfg.UsernameAssertionKey}}http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name{{else}}{{$cfg.UsernameAssertionKey}}{{end}}">
</div>
{{end}}
Expand Down Expand Up @@ -506,6 +499,9 @@
<h5>GMail Settings:</h5>
<p>Host: smtp.gmail.com, Port: 587, Enable TLS Encryption: true</p>

<h5>SAML Settings:</h5>
<p>{{ctx.Locale.Tr "admin.auths.tips.saml"}}</p>

<h5 class="oauth2">{{ctx.Locale.Tr "admin.auths.tips.oauth2.general"}}:</h5>
<p class="oauth2">{{ctx.Locale.Tr "admin.auths.tips.oauth2.general.tip"}} <b id="oauth2-callback-url"></b></p>
</div>
Expand Down
3 changes: 3 additions & 0 deletions templates/admin/auth/new.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@
<h5>GMail Settings:</h5>
<p>Host: smtp.gmail.com, Port: 587, Enable TLS Encryption: true</p>

<h5>SAML Settings:</h5>
<p>{{ctx.Locale.Tr "admin.auths.tips.saml"}}</p>

<h5 class="oauth2">{{ctx.Locale.Tr "admin.auths.tips.oauth2.general"}}:</h5>
<p class="oauth2">{{ctx.Locale.Tr "admin.auths.tips.oauth2.general.tip"}} <b id="oauth2-callback-url"></b></p>

Expand Down
11 changes: 2 additions & 9 deletions templates/admin/auth/source/saml.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,15 @@
</div>
</div>

<div class=" field">
<div class="field">
<label for="service_provider_certificate">{{ctx.Locale.Tr "admin.auths.saml_service_provider_certificate"}}</label>
<textarea rows=2 id="service_provider_certificate" name="service_provider_certificate" value="{{.ServiceProviderCertificate}}"></textarea>
</div>
<div class=" field">
<div class="field">
<label for="service_provider_private_key">{{ctx.Locale.Tr "admin.auths.saml_service_provider_private_key"}}</label>
<textarea rows=2 id="service_provider_private_key" name="service_provider_private_key" value="{{.ServiceProviderPrivateKey}}"></textarea>
</div>

<div class="inline field">
<div class="ui checkbox">
<label><strong>{{ctx.Locale.Tr "admin.auths.saml_sign_requests"}}</strong></label>
<input name="sign_requests" type="checkbox" {{if .SignRequests}}checked{{end}}>
</div>
</div>

<div class="field">
<label for="email_assertion_key">{{ctx.Locale.Tr "admin.auths.saml_identity_provider_email_assertion_key"}}</label>
<input id="email_assertion_key" name="email_assertion_key" value="{{if not .EmailAssertionKey}}http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress{{else}}{{.EmailAssertionKey}}{{end}}">
Expand Down
1 change: 0 additions & 1 deletion tests/integration/saml_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ func TestSAMLRegistration(t *testing.T) {
NameIDFormat: 4,
ServiceProviderCertificate: "",
ServiceProviderPrivateKey: "",
SignRequests: false,
EmailAssertionKey: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
NameAssertionKey: "http://schemas.xmlsoap.org/claims/CommonName",
UsernameAssertionKey: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
Expand Down
Loading