Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

source_callout.go 2.6KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. // Copyright 2023 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package saml
  4. import (
  5. "fmt"
  6. "net/http"
  7. "strings"
  8. "github.com/markbates/goth"
  9. )
  10. // Callout redirects request/response pair to authenticate against the provider
  11. func (source *Source) Callout(request *http.Request, response http.ResponseWriter) error {
  12. samlRWMutex.RLock()
  13. defer samlRWMutex.RUnlock()
  14. if _, ok := providers[source.authSource.Name]; !ok {
  15. return fmt.Errorf("no provider for this saml")
  16. }
  17. authURL, err := providers[source.authSource.Name].samlSP.BuildAuthURL("")
  18. if err == nil {
  19. http.Redirect(response, request, authURL, http.StatusTemporaryRedirect)
  20. }
  21. return err
  22. }
  23. // Callback handles SAML callback, resolve to a goth user and send back to original url
  24. // this will trigger a new authentication request, but because we save it in the session we can use that
  25. func (source *Source) Callback(request *http.Request, response http.ResponseWriter) (goth.User, error) {
  26. samlRWMutex.RLock()
  27. defer samlRWMutex.RUnlock()
  28. user := goth.User{
  29. Provider: source.authSource.Name,
  30. }
  31. samlResponse := request.FormValue("SAMLResponse")
  32. assertions, err := source.samlSP.RetrieveAssertionInfo(samlResponse)
  33. if err != nil {
  34. return user, err
  35. }
  36. if assertions.WarningInfo.OneTimeUse {
  37. return user, fmt.Errorf("SAML response contains one time use warning")
  38. }
  39. if assertions.WarningInfo.ProxyRestriction != nil {
  40. return user, fmt.Errorf("SAML response contains proxy restriction warning: %v", assertions.WarningInfo.ProxyRestriction)
  41. }
  42. if assertions.WarningInfo.NotInAudience {
  43. return user, fmt.Errorf("SAML response contains audience warning")
  44. }
  45. if assertions.WarningInfo.InvalidTime {
  46. return user, fmt.Errorf("SAML response contains invalid time warning")
  47. }
  48. samlMap := make(map[string]string)
  49. for key, value := range assertions.Values {
  50. keyParsed := strings.ToLower(key[strings.LastIndex(key, "/")+1:]) // Uses the trailing slug as the key name.
  51. valueParsed := value.Values[0].Value
  52. samlMap[keyParsed] = valueParsed
  53. }
  54. user.UserID = assertions.NameID
  55. if user.UserID == "" {
  56. return user, fmt.Errorf("no nameID found in SAML response")
  57. }
  58. // email
  59. if _, ok := samlMap[source.EmailAssertionKey]; !ok {
  60. user.Email = samlMap[source.EmailAssertionKey]
  61. }
  62. // name
  63. if _, ok := samlMap[source.NameAssertionKey]; !ok {
  64. user.NickName = samlMap[source.NameAssertionKey]
  65. }
  66. // username
  67. if _, ok := samlMap[source.UsernameAssertionKey]; !ok {
  68. user.Name = samlMap[source.UsernameAssertionKey]
  69. }
  70. // TODO: utilize groups once mapping is supported
  71. return user, nil
  72. }