aboutsummaryrefslogtreecommitdiffstats
path: root/modules/auth/sso/sso.go
diff options
context:
space:
mode:
Diffstat (limited to 'modules/auth/sso/sso.go')
-rw-r--r--modules/auth/sso/sso.go141
1 files changed, 141 insertions, 0 deletions
diff --git a/modules/auth/sso/sso.go b/modules/auth/sso/sso.go
new file mode 100644
index 0000000000..cf8148d89b
--- /dev/null
+++ b/modules/auth/sso/sso.go
@@ -0,0 +1,141 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Copyright 2019 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package sso
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+
+ "code.gitea.io/gitea/models"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/setting"
+
+ "gitea.com/macaron/macaron"
+ "gitea.com/macaron/session"
+)
+
+// ssoMethods contains the list of SSO authentication plugins in the order they are expected to be
+// executed.
+//
+// The OAuth2 plugin is expected to be executed first, as it must ignore the user id stored
+// in the session (if there is a user id stored in session other plugins might return the user
+// object for that id).
+//
+// The Session plugin is expected to be executed second, in order to skip authentication
+// for users that have already signed in.
+var ssoMethods = []SingleSignOn{
+ &OAuth2{},
+ &Session{},
+ &ReverseProxy{},
+ &Basic{},
+}
+
+// The purpose of the following three function variables is to let the linter know that
+// those functions are not dead code and are actually being used
+var (
+ _ = handleSignIn
+)
+
+// Methods returns the instances of all registered SSO methods
+func Methods() []SingleSignOn {
+ return ssoMethods
+}
+
+// Register adds the specified instance to the list of available SSO methods
+func Register(method SingleSignOn) {
+ ssoMethods = append(ssoMethods, method)
+}
+
+// Init should be called exactly once when the application starts to allow SSO plugins
+// to allocate necessary resources
+func Init() {
+ for _, method := range Methods() {
+ err := method.Init()
+ if err != nil {
+ log.Error("Could not initialize '%s' SSO method, error: %s", reflect.TypeOf(method).String(), err)
+ }
+ }
+}
+
+// Free should be called exactly once when the application is terminating to allow SSO plugins
+// to release necessary resources
+func Free() {
+ for _, method := range Methods() {
+ err := method.Free()
+ if err != nil {
+ log.Error("Could not free '%s' SSO method, error: %s", reflect.TypeOf(method).String(), err)
+ }
+ }
+}
+
+// SessionUser returns the user object corresponding to the "uid" session variable.
+func SessionUser(sess session.Store) *models.User {
+ // Get user ID
+ uid := sess.Get("uid")
+ if uid == nil {
+ return nil
+ }
+ id, ok := uid.(int64)
+ if !ok {
+ return nil
+ }
+
+ // Get user object
+ user, err := models.GetUserByID(id)
+ if err != nil {
+ if !models.IsErrUserNotExist(err) {
+ log.Error("GetUserById: %v", err)
+ }
+ return nil
+ }
+ return user
+}
+
+// isAPIPath returns true if the specified URL is an API path
+func isAPIPath(ctx *macaron.Context) bool {
+ return strings.HasPrefix(ctx.Req.URL.Path, "/api/")
+}
+
+// isAttachmentDownload check if request is a file download (GET) with URL to an attachment
+func isAttachmentDownload(ctx *macaron.Context) bool {
+ return strings.HasPrefix(ctx.Req.URL.Path, "/attachments/") && ctx.Req.Method == "GET"
+}
+
+// handleSignIn clears existing session variables and stores new ones for the specified user object
+func handleSignIn(ctx *macaron.Context, sess session.Store, user *models.User) {
+ _ = sess.Delete("openid_verified_uri")
+ _ = sess.Delete("openid_signin_remember")
+ _ = sess.Delete("openid_determined_email")
+ _ = sess.Delete("openid_determined_username")
+ _ = sess.Delete("twofaUid")
+ _ = sess.Delete("twofaRemember")
+ _ = sess.Delete("u2fChallenge")
+ _ = sess.Delete("linkAccount")
+ err := sess.Set("uid", user.ID)
+ if err != nil {
+ log.Error(fmt.Sprintf("Error setting session: %v", err))
+ }
+ err = sess.Set("uname", user.Name)
+ if err != nil {
+ log.Error(fmt.Sprintf("Error setting session: %v", err))
+ }
+
+ // Language setting of the user overwrites the one previously set
+ // If the user does not have a locale set, we save the current one.
+ if len(user.Language) == 0 {
+ user.Language = ctx.Locale.Language()
+ if err := models.UpdateUserCols(user, "language"); err != nil {
+ log.Error(fmt.Sprintf("Error updating user language [user: %d, locale: %s]", user.ID, user.Language))
+ return
+ }
+ }
+
+ ctx.SetCookie("lang", user.Language, nil, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
+
+ // Clear whatever CSRF has right now, force to generate a new one
+ ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
+}