mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-26 12:27:06 +00:00 
			
		
		
		
	Oauth2 consumer (#679)
* initial stuff for oauth2 login, fails on: * login button on the signIn page to start the OAuth2 flow and a callback for each provider Only GitHub is implemented for now * show login button only when the OAuth2 consumer is configured (and activated) * create macaron group for oauth2 urls * prevent net/http in modules (other then oauth2) * use a new data sessions oauth2 folder for storing the oauth2 session data * add missing 2FA when this is enabled on the user * add password option for OAuth2 user , for use with git over http and login to the GUI * add tip for registering a GitHub OAuth application * at startup of Gitea register all configured providers and also on adding/deleting of new providers * custom handling of errors in oauth2 request init + show better tip * add ExternalLoginUser model and migration script to add it to database * link a external account to an existing account (still need to handle wrong login and signup) and remove if user is removed * remove the linked external account from the user his settings * if user is unknown we allow him to register a new account or link it to some existing account * sign up with button on signin page (als change OAuth2Provider structure so we can store basic stuff about providers) * from gorilla/sessions docs: "Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler as or else you will leak memory!" (we're using gorilla/sessions for storing oauth2 sessions) * use updated goth lib that now supports getting the OAuth2 user if the AccessToken is still valid instead of re-authenticating (prevent flooding the OAuth2 provider)
This commit is contained in:
		 Willem van Dreumel
					Willem van Dreumel
				
			
				
					committed by
					
						 Kim "BKC" Carlbäcker
						Kim "BKC" Carlbäcker
					
				
			
			
				
	
			
			
			 Kim "BKC" Carlbäcker
						Kim "BKC" Carlbäcker
					
				
			
						parent
						
							fd941db246
						
					
				
				
					commit
					01d957677f
				
			
							
								
								
									
										105
									
								
								modules/auth/oauth2/oauth2.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								modules/auth/oauth2/oauth2.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,105 @@ | ||||
| // Copyright 2017 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 oauth2 | ||||
|  | ||||
| import ( | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| 	"code.gitea.io/gitea/modules/log" | ||||
| 	"github.com/gorilla/sessions" | ||||
| 	"github.com/markbates/goth" | ||||
| 	"github.com/markbates/goth/gothic" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
| 	"github.com/satori/go.uuid" | ||||
| 	"path/filepath" | ||||
| 	"github.com/markbates/goth/providers/github" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	sessionUsersStoreKey = "gitea-oauth2-sessions" | ||||
| 	providerHeaderKey    = "gitea-oauth2-provider" | ||||
| ) | ||||
|  | ||||
| // Init initialize the setup of the OAuth2 library | ||||
| func Init() { | ||||
| 	sessionDir := filepath.Join(setting.AppDataPath, "sessions", "oauth2") | ||||
| 	if err := os.MkdirAll(sessionDir, 0700); err != nil { | ||||
| 		log.Fatal(4, "Fail to create dir %s: %v", sessionDir, err) | ||||
| 	} | ||||
|  | ||||
| 	gothic.Store = sessions.NewFilesystemStore(sessionDir, []byte(sessionUsersStoreKey)) | ||||
|  | ||||
| 	gothic.SetState = func(req *http.Request) string { | ||||
| 		return uuid.NewV4().String() | ||||
| 	} | ||||
|  | ||||
| 	gothic.GetProviderName = func(req *http.Request) (string, error) { | ||||
| 		return req.Header.Get(providerHeaderKey), nil | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| // Auth OAuth2 auth service | ||||
| func Auth(provider string, request *http.Request, response http.ResponseWriter) error { | ||||
| 	// not sure if goth is thread safe (?) when using multiple providers | ||||
| 	request.Header.Set(providerHeaderKey, provider) | ||||
|  | ||||
| 	// don't use the default gothic begin handler to prevent issues when some error occurs | ||||
| 	// normally the gothic library will write some custom stuff to the response instead of our own nice error page | ||||
| 	//gothic.BeginAuthHandler(response, request) | ||||
|  | ||||
| 	url, err := gothic.GetAuthURL(response, request) | ||||
| 	if err == nil { | ||||
| 		http.Redirect(response, request, url, http.StatusTemporaryRedirect) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // ProviderCallback handles OAuth 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 ProviderCallback(provider string, request *http.Request, response http.ResponseWriter) (goth.User, error) { | ||||
| 	// not sure if goth is thread safe (?) when using multiple providers | ||||
| 	request.Header.Set(providerHeaderKey, provider) | ||||
|  | ||||
| 	user, err := gothic.CompleteUserAuth(response, request) | ||||
| 	if err != nil { | ||||
| 		return user, err | ||||
| 	} | ||||
|  | ||||
| 	return user, nil | ||||
| } | ||||
|  | ||||
| // RegisterProvider register a OAuth2 provider in goth lib | ||||
| func RegisterProvider(providerName, providerType, clientID, clientSecret string) { | ||||
| 	provider := createProvider(providerName, providerType, clientID, clientSecret) | ||||
|  | ||||
| 	if provider != nil { | ||||
| 		goth.UseProviders(provider) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // RemoveProvider removes the given OAuth2 provider from the goth lib | ||||
| func RemoveProvider(providerName string) { | ||||
| 	delete(goth.GetProviders(), providerName) | ||||
| } | ||||
|  | ||||
| // used to create different types of goth providers | ||||
| func createProvider(providerName, providerType, clientID, clientSecret string) goth.Provider { | ||||
| 	callbackURL := setting.AppURL + "user/oauth2/" + providerName + "/callback" | ||||
|  | ||||
| 	var provider goth.Provider | ||||
|  | ||||
| 	switch providerType { | ||||
| 	case "github": | ||||
| 		provider = github.New(clientID, clientSecret, callbackURL, "user:email") | ||||
| 	} | ||||
|  | ||||
| 	// always set the name if provider is created so we can support multiple setups of 1 provider | ||||
| 	if provider != nil { | ||||
| 		provider.SetName(providerName) | ||||
| 	} | ||||
|  | ||||
| 	return provider | ||||
| } | ||||
		Reference in New Issue
	
	Block a user