mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-30 06:38:37 -04: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:
		
				
					committed by
					
						 Kim "BKC" Carlbäcker
						Kim "BKC" Carlbäcker
					
				
			
			
				
	
			
			
			
						parent
						
							fd941db246
						
					
				
				
					commit
					01d957677f
				
			
							
								
								
									
										199
									
								
								vendor/github.com/gorilla/sessions/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								vendor/github.com/gorilla/sessions/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,199 @@ | ||||
| // Copyright 2012 The Gorilla Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| /* | ||||
| Package sessions provides cookie and filesystem sessions and | ||||
| infrastructure for custom session backends. | ||||
|  | ||||
| The key features are: | ||||
|  | ||||
| 	* Simple API: use it as an easy way to set signed (and optionally | ||||
| 	  encrypted) cookies. | ||||
| 	* Built-in backends to store sessions in cookies or the filesystem. | ||||
| 	* Flash messages: session values that last until read. | ||||
| 	* Convenient way to switch session persistency (aka "remember me") and set | ||||
| 	  other attributes. | ||||
| 	* Mechanism to rotate authentication and encryption keys. | ||||
| 	* Multiple sessions per request, even using different backends. | ||||
| 	* Interfaces and infrastructure for custom session backends: sessions from | ||||
| 	  different stores can be retrieved and batch-saved using a common API. | ||||
|  | ||||
| Let's start with an example that shows the sessions API in a nutshell: | ||||
|  | ||||
| 	import ( | ||||
| 		"net/http" | ||||
| 		"github.com/gorilla/sessions" | ||||
| 	) | ||||
|  | ||||
| 	var store = sessions.NewCookieStore([]byte("something-very-secret")) | ||||
|  | ||||
| 	func MyHandler(w http.ResponseWriter, r *http.Request) { | ||||
| 		// Get a session. We're ignoring the error resulted from decoding an | ||||
| 		// existing session: Get() always returns a session, even if empty. | ||||
| 		session, err := store.Get(r, "session-name") | ||||
| 		if err != nil { | ||||
| 			http.Error(w, err.Error(), http.StatusInternalServerError) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		// Set some session values. | ||||
| 		session.Values["foo"] = "bar" | ||||
| 		session.Values[42] = 43 | ||||
| 		// Save it before we write to the response/return from the handler. | ||||
| 		session.Save(r, w) | ||||
| 	} | ||||
|  | ||||
| First we initialize a session store calling NewCookieStore() and passing a | ||||
| secret key used to authenticate the session. Inside the handler, we call | ||||
| store.Get() to retrieve an existing session or a new one. Then we set some | ||||
| session values in session.Values, which is a map[interface{}]interface{}. | ||||
| And finally we call session.Save() to save the session in the response. | ||||
|  | ||||
| Note that in production code, we should check for errors when calling | ||||
| session.Save(r, w), and either display an error message or otherwise handle it. | ||||
|  | ||||
| Save must be called before writing to the response, otherwise the session | ||||
| cookie will not be sent to the client. | ||||
|  | ||||
| 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! An easy way to do this | ||||
| is to wrap the top-level mux when calling http.ListenAndServe: | ||||
|  | ||||
|     http.ListenAndServe(":8080", context.ClearHandler(http.DefaultServeMux)) | ||||
|  | ||||
| The ClearHandler function is provided by the gorilla/context package. | ||||
|  | ||||
| That's all you need to know for the basic usage. Let's take a look at other | ||||
| options, starting with flash messages. | ||||
|  | ||||
| Flash messages are session values that last until read. The term appeared with | ||||
| Ruby On Rails a few years back. When we request a flash message, it is removed | ||||
| from the session. To add a flash, call session.AddFlash(), and to get all | ||||
| flashes, call session.Flashes(). Here is an example: | ||||
|  | ||||
| 	func MyHandler(w http.ResponseWriter, r *http.Request) { | ||||
| 		// Get a session. | ||||
| 		session, err := store.Get(r, "session-name") | ||||
| 		if err != nil { | ||||
| 			http.Error(w, err.Error(), http.StatusInternalServerError) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		// Get the previously flashes, if any. | ||||
| 		if flashes := session.Flashes(); len(flashes) > 0 { | ||||
| 			// Use the flash values. | ||||
| 		} else { | ||||
| 			// Set a new flash. | ||||
| 			session.AddFlash("Hello, flash messages world!") | ||||
| 		} | ||||
| 		session.Save(r, w) | ||||
| 	} | ||||
|  | ||||
| Flash messages are useful to set information to be read after a redirection, | ||||
| like after form submissions. | ||||
|  | ||||
| There may also be cases where you want to store a complex datatype within a | ||||
| session, such as a struct. Sessions are serialised using the encoding/gob package, | ||||
| so it is easy to register new datatypes for storage in sessions: | ||||
|  | ||||
| 	import( | ||||
| 		"encoding/gob" | ||||
| 		"github.com/gorilla/sessions" | ||||
| 	) | ||||
|  | ||||
| 	type Person struct { | ||||
| 		FirstName	string | ||||
| 		LastName 	string | ||||
| 		Email		string | ||||
| 		Age			int | ||||
| 	} | ||||
|  | ||||
| 	type M map[string]interface{} | ||||
|  | ||||
| 	func init() { | ||||
|  | ||||
| 		gob.Register(&Person{}) | ||||
| 		gob.Register(&M{}) | ||||
| 	} | ||||
|  | ||||
| As it's not possible to pass a raw type as a parameter to a function, gob.Register() | ||||
| relies on us passing it a value of the desired type. In the example above we've passed | ||||
| it a pointer to a struct and a pointer to a custom type representing a | ||||
| map[string]interface. (We could have passed non-pointer values if we wished.) This will | ||||
| then allow us to serialise/deserialise values of those types to and from our sessions. | ||||
|  | ||||
| Note that because session values are stored in a map[string]interface{}, there's | ||||
| a need to type-assert data when retrieving it. We'll use the Person struct we registered above: | ||||
|  | ||||
| 	func MyHandler(w http.ResponseWriter, r *http.Request) { | ||||
| 		session, err := store.Get(r, "session-name") | ||||
| 		if err != nil { | ||||
| 			http.Error(w, err.Error(), http.StatusInternalServerError) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		// Retrieve our struct and type-assert it | ||||
| 		val := session.Values["person"] | ||||
| 		var person = &Person{} | ||||
| 		if person, ok := val.(*Person); !ok { | ||||
| 			// Handle the case that it's not an expected type | ||||
| 		} | ||||
|  | ||||
| 		// Now we can use our person object | ||||
| 	} | ||||
|  | ||||
| By default, session cookies last for a month. This is probably too long for | ||||
| some cases, but it is easy to change this and other attributes during | ||||
| runtime. Sessions can be configured individually or the store can be | ||||
| configured and then all sessions saved using it will use that configuration. | ||||
| We access session.Options or store.Options to set a new configuration. The | ||||
| fields are basically a subset of http.Cookie fields. Let's change the | ||||
| maximum age of a session to one week: | ||||
|  | ||||
| 	session.Options = &sessions.Options{ | ||||
| 		Path:     "/", | ||||
| 		MaxAge:   86400 * 7, | ||||
| 		HttpOnly: true, | ||||
| 	} | ||||
|  | ||||
| Sometimes we may want to change authentication and/or encryption keys without | ||||
| breaking existing sessions. The CookieStore supports key rotation, and to use | ||||
| it you just need to set multiple authentication and encryption keys, in pairs, | ||||
| to be tested in order: | ||||
|  | ||||
| 	var store = sessions.NewCookieStore( | ||||
| 		[]byte("new-authentication-key"), | ||||
| 		[]byte("new-encryption-key"), | ||||
| 		[]byte("old-authentication-key"), | ||||
| 		[]byte("old-encryption-key"), | ||||
| 	) | ||||
|  | ||||
| New sessions will be saved using the first pair. Old sessions can still be | ||||
| read because the first pair will fail, and the second will be tested. This | ||||
| makes it easy to "rotate" secret keys and still be able to validate existing | ||||
| sessions. Note: for all pairs the encryption key is optional; set it to nil | ||||
| or omit it and and encryption won't be used. | ||||
|  | ||||
| Multiple sessions can be used in the same request, even with different | ||||
| session backends. When this happens, calling Save() on each session | ||||
| individually would be cumbersome, so we have a way to save all sessions | ||||
| at once: it's sessions.Save(). Here's an example: | ||||
|  | ||||
| 	var store = sessions.NewCookieStore([]byte("something-very-secret")) | ||||
|  | ||||
| 	func MyHandler(w http.ResponseWriter, r *http.Request) { | ||||
| 		// Get a session and set a value. | ||||
| 		session1, _ := store.Get(r, "session-one") | ||||
| 		session1.Values["foo"] = "bar" | ||||
| 		// Get another session and set another value. | ||||
| 		session2, _ := store.Get(r, "session-two") | ||||
| 		session2.Values[42] = 43 | ||||
| 		// Save all sessions. | ||||
| 		sessions.Save(r, w) | ||||
| 	} | ||||
|  | ||||
| This is possible because when we call Get() from a session store, it adds the | ||||
| session to a common registry. Save() uses it to save all registered sessions. | ||||
| */ | ||||
| package sessions | ||||
		Reference in New Issue
	
	Block a user