Documentation ¶
Overview ¶
Package htsec provides security detail for your endpoints.
The security detail with it's guards is used to authorize requests. Once authorized a slip with e.g. name, email and toke is returned for further use.
In the oauth2 flow the state is
GUARDNAME.RANDOM.SIGNATURE.DESTINATION
The random value, signature and security detail private key are used to verify the state.
The destination part can be used by you as a way to redirect users to whatever they wanted to get in the first place.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var ( // ErrState indicates something in the state data is invalid ErrState = fmt.Errorf("state") // ErrNotFound indicates named guard is not found ErrNotFound = fmt.Errorf("not found") )
Functions ¶
This section is empty.
Types ¶
type SecurityDetail ¶ added in v0.2.0
type SecurityDetail struct { // PrivateKey is used to verify the state during authorization. PrivateKey []byte // contains filtered or unexported fields }
Example (Setup) ¶
package main import ( "fmt" "net/http" "github.com/gregoryv/htsec" "github.com/gregoryv/htsec/github" "github.com/gregoryv/htsec/google" ) // For a more complete example, see // https://github.com/gregoryv/servant func main() { sec := htsec.NewSecurityDetail( // define guards that will protect resources github.Guard(), google.Guard(), ) h := NewRouter(sec) http.ListenAndServe(":8080", h) } func NewRouter(sec *htsec.SecurityDetail) *http.ServeMux { mx := http.NewServeMux() mx.HandleFunc("/{$}", frontpage) mx.Handle("/login", login(sec)) // reuse the same callback endpoint mx.Handle("/oauth/redirect", callback(sec)) // everything else is private mx.Handle("/", private()) return mx } func frontpage(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, `Login: <a href="/login?use=github">github</a>, <a href="/login?use=google>google></a>`, ) } // login handles requests for selecting login method func login(sec *htsec.SecurityDetail) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { name := r.URL.Query().Get("use") url, err := sec.GuardURL(name, "/") if err != nil { http.Redirect(w, r, "/", http.StatusSeeOther) return } http.Redirect(w, r, url, http.StatusTemporaryRedirect) } } func callback(sec *htsec.SecurityDetail) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { slip, err := sec.Authorize(r) if err != nil { w.WriteHeader(http.StatusUnauthorized) return } // setup session ... _ = slip http.Redirect(w, r, "/inside", http.StatusSeeOther) } } // private returns handler of all protected endpoints func private() http.Handler { mx := http.NewServeMux() mx.HandleFunc("/inside", inside) return protect(mx) } // protect wraps the given handler func protect(next http.Handler) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // verify session, see callback //if err := sessionValid(r); err != nil { // http.Redirect(w, r, "/", http.StatusSeeOther) // return //} next.ServeHTTP(w, r) } } func inside(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "You are inside!") }
Output:
func NewSecurityDetail ¶ added in v0.2.0
func NewSecurityDetail(guards ...*Guard) *SecurityDetail
NewSecurityDetail returns a new group of guards. Names must be unique and PrivateKey is a random 32 byte slice.
type Slip ¶
type Slip struct { // GUARDNAME.RANDOM.SIGNATURE.DESTINATION // // GUARNAME - identifies the guard used // RANDOM - a random server side string used during verification // SIGNATURE - signature of the state based on the security detail private key // DESTINATION - the protected path you wanted to reach State string Token *oauth2.Token // Name of the authorized account Name string // Email of the authorized account Email string }
func (*Slip) Destination ¶ added in v0.2.0
Destination returns the DESTINATION part of the state or empty if invalid.
Click to show internal directories.
Click to hide internal directories.