git.iko.soy/typeable/oauth2-proxy
on cdcc620 help sign in
105 lines 3.8 kB history raw
1package middleware
3import (
4 "fmt"
5 "net/http"
7 "github.com/justinas/alice"
8 middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
9 sessionsapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
10 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/authentication/basic"
11 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
14func NewBasicAuthSessionLoader(validator basic.Validator, sessionGroups []string, preferEmail bool) alice.Constructor {
15 return func(next http.Handler) http.Handler {
16 return loadBasicAuthSession(validator, sessionGroups, preferEmail, next)
17 }
20// loadBasicAuthSession attmepts to load a session from basic auth credentials
21// stored in an Authorization header within the request.
22// If no authorization header is found, or the header is invalid, no session
23// will be loaded and the request will be passed to the next handler.
24// If a session was loaded by a previous handler, it will not be replaced.
25func loadBasicAuthSession(validator basic.Validator, sessionGroups []string, preferEmail bool, next http.Handler) http.Handler {
26 // This is a hack to be backwards compatible with the old PreferEmailToUser option.
27 // Long term we will have a rich static user configuration option and this will
28 // be removed.
29 // TODO(JoelSpeed): Remove this hack once rich static user config is implemented.
30 getSession := getBasicSession
31 if preferEmail {
32 getSession = func(validator basic.Validator, sessionGroups []string, req *http.Request) (*sessionsapi.SessionState, error) {
33 session, err := getBasicSession(validator, sessionGroups, req)
34 if session != nil {
35 session.Email = session.User
36 }
37 return session, err
38 }
39 }
41 return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
42 scope := middlewareapi.GetRequestScope(req)
43 // If scope is nil, this will panic.
44 // A scope should always be injected before this handler is called.
45 if scope.Session != nil {
46 // The session was already loaded, pass to the next handler
47 next.ServeHTTP(rw, req)
48 return
49 }
51 session, err := getSession(validator, sessionGroups, req)
52 if err != nil {
53 logger.Errorf("Error retrieving session from token in Authorization header: %v", err)
54 }
56 // Add the session to the scope if it was found
57 scope.Session = session
58 next.ServeHTTP(rw, req)
59 })
62// getBasicSession attempts to load a basic session from the request.
63// If the credentials in the request exist within the htpasswdMap,
64// a new session will be created.
65func getBasicSession(validator basic.Validator, sessionGroups []string, req *http.Request) (*sessionsapi.SessionState, error) {
66 auth := req.Header.Get("Authorization")
67 if auth == "" {
68 // No auth header provided, so don't attempt to load a session
69 return nil, nil
70 }
72 user, password, err := findBasicCredentialsFromHeader(auth)
73 if err != nil {
74 return nil, err
75 }
77 if validator.Validate(user, password) {
78 logger.PrintAuthf(user, req, logger.AuthSuccess, "Authenticated via basic auth and HTpasswd File")
80 return &sessionsapi.SessionState{User: user, Groups: sessionGroups}, nil
81 }
83 logger.PrintAuthf(user, req, logger.AuthFailure, "Invalid authentication via basic auth: not in Htpasswd File")
84 return nil, nil
87// findBasicCredentialsFromHeader finds basic auth credneitals from the
88// Authorization header of a given request.
89func findBasicCredentialsFromHeader(header string) (string, string, error) {
90 tokenType, token, err := splitAuthHeader(header)
91 if err != nil {
92 return "", "", err
93 }
95 if tokenType != "Basic" {
96 return "", "", fmt.Errorf("invalid Authorization header: %q", header)
97 }
99 user, password, err := getBasicAuthCredentials(token)
100 if err != nil {
101 return "", "", fmt.Errorf("error decoding basic auth credentials: %v", err)
102 }
104 return user, password, nil