1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889 |
- // Copyright 2023 The Gitea Authors. All rights reserved.
- // SPDX-License-Identifier: MIT
-
- package saml
-
- import (
- "fmt"
- "net/http"
- "strings"
-
- "github.com/markbates/goth"
- )
-
- // Callout redirects request/response pair to authenticate against the provider
- func (source *Source) Callout(request *http.Request, response http.ResponseWriter) error {
- samlRWMutex.RLock()
- defer samlRWMutex.RUnlock()
- if _, ok := providers[source.authSource.Name]; !ok {
- return fmt.Errorf("no provider for this saml")
- }
-
- authURL, err := providers[source.authSource.Name].samlSP.BuildAuthURL("")
- if err == nil {
- http.Redirect(response, request, authURL, http.StatusTemporaryRedirect)
- }
- return err
- }
-
- // Callback handles SAML callback, resolve to a goth user and send back to original url
- // this will trigger a new authentication request, but because we save it in the session we can use that
- func (source *Source) Callback(request *http.Request, response http.ResponseWriter) (goth.User, error) {
- samlRWMutex.RLock()
- defer samlRWMutex.RUnlock()
-
- user := goth.User{
- Provider: source.authSource.Name,
- }
- samlResponse := request.FormValue("SAMLResponse")
- assertions, err := source.samlSP.RetrieveAssertionInfo(samlResponse)
- if err != nil {
- return user, err
- }
-
- if assertions.WarningInfo.OneTimeUse {
- return user, fmt.Errorf("SAML response contains one time use warning")
- }
-
- if assertions.WarningInfo.ProxyRestriction != nil {
- return user, fmt.Errorf("SAML response contains proxy restriction warning: %v", assertions.WarningInfo.ProxyRestriction)
- }
-
- if assertions.WarningInfo.NotInAudience {
- return user, fmt.Errorf("SAML response contains audience warning")
- }
-
- if assertions.WarningInfo.InvalidTime {
- return user, fmt.Errorf("SAML response contains invalid time warning")
- }
-
- samlMap := make(map[string]string)
- for key, value := range assertions.Values {
- keyParsed := strings.ToLower(key[strings.LastIndex(key, "/")+1:]) // Uses the trailing slug as the key name.
- valueParsed := value.Values[0].Value
- samlMap[keyParsed] = valueParsed
-
- }
-
- user.UserID = assertions.NameID
- if user.UserID == "" {
- return user, fmt.Errorf("no nameID found in SAML response")
- }
-
- // email
- if _, ok := samlMap[source.EmailAssertionKey]; !ok {
- user.Email = samlMap[source.EmailAssertionKey]
- }
- // name
- if _, ok := samlMap[source.NameAssertionKey]; !ok {
- user.NickName = samlMap[source.NameAssertionKey]
- }
- // username
- if _, ok := samlMap[source.UsernameAssertionKey]; !ok {
- user.Name = samlMap[source.UsernameAssertionKey]
- }
-
- // TODO: utilize groups once mapping is supported
-
- return user, nil
- }
|