mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-19 00:36:38 +00:00
simplify authentication
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
<!doctype html>
|
||||
{{ range . }}
|
||||
{{ if eq .Key "pin" }}
|
||||
{{ range $method, $value := .Methods }}
|
||||
{{ if eq $method "pin" }}
|
||||
<form>
|
||||
<input name={{ . }} />
|
||||
<label for={{ $value }}>PIN:</label>
|
||||
<input name={{ $value }} id={{ $value }} />
|
||||
<button type=submit></button>
|
||||
</form>
|
||||
{{ else if eq .Key "password" }}
|
||||
{{ else if eq $method "password" }}
|
||||
<form>
|
||||
<input name={{ . }} />
|
||||
<label for={{ $value }}>Password:</label>
|
||||
<input name={{ $value }} id={{ $value }}/>
|
||||
<button type=submit></button>
|
||||
</form>
|
||||
{{ end }}
|
||||
|
||||
@@ -25,7 +25,7 @@ func (Link) Type() Method {
|
||||
return MethodLink
|
||||
}
|
||||
|
||||
func (l Link) Authenticate(r *http.Request) (string, bool, any) {
|
||||
func (l Link) Authenticate(r *http.Request) (string, string) {
|
||||
email := r.FormValue(linkFormId)
|
||||
|
||||
res, err := l.client.Authenticate(r.Context(), &proto.AuthenticateRequest{
|
||||
@@ -40,15 +40,15 @@ func (l Link) Authenticate(r *http.Request) (string, bool, any) {
|
||||
})
|
||||
if err != nil {
|
||||
// TODO: log error here
|
||||
return "", false, linkFormId
|
||||
return "", linkFormId
|
||||
}
|
||||
|
||||
if res.GetSuccess() {
|
||||
// Use the email address as the user identifier.
|
||||
return email, true, nil
|
||||
return email, ""
|
||||
}
|
||||
|
||||
return "", false, linkFormId
|
||||
return "", linkFormId
|
||||
}
|
||||
|
||||
func (l Link) Middleware(next http.Handler) http.Handler {
|
||||
|
||||
@@ -53,10 +53,8 @@ type Scheme interface {
|
||||
// an empty string should indicate an unauthenticated request which
|
||||
// will be rejected; optionally, it can also return any data that should
|
||||
// be included in a UI template when prompting the user to authenticate.
|
||||
// If the request is authenticated, then a user id should be returned
|
||||
// along with a boolean indicating whether a redirect is needed to clean
|
||||
// up authentication artifacts from the URLs query.
|
||||
Authenticate(*http.Request) (userid string, needsRedirect bool, promptData any)
|
||||
// If the request is authenticated, then a user id should be returned.
|
||||
Authenticate(*http.Request) (userid string, promptData string)
|
||||
// Middleware is applied within the outer auth middleware, but they will
|
||||
// be applied after authentication if no scheme has authenticated a
|
||||
// request.
|
||||
@@ -119,32 +117,30 @@ func (mw *Middleware) Protect(next http.Handler) http.Handler {
|
||||
}
|
||||
|
||||
// Try to authenticate with each scheme.
|
||||
methods := make(map[Method]any)
|
||||
methods := make(map[string]string)
|
||||
for _, s := range schemes {
|
||||
userid, needsRedirect, promptData := s.Authenticate(r)
|
||||
userid, promptData := s.Authenticate(r)
|
||||
if userid != "" {
|
||||
mw.createSession(w, r, userid, s.Type())
|
||||
if needsRedirect {
|
||||
// Clean the path and redirect to the naked URL.
|
||||
// This is intended to prevent leaking potentially
|
||||
// sensitive query parameters for some authentication
|
||||
// methods such as OIDC.
|
||||
http.Redirect(w, r, r.URL.Path, http.StatusFound)
|
||||
return
|
||||
}
|
||||
ctx := withAuthMethod(r.Context(), s.Type())
|
||||
ctx = withAuthUser(ctx, userid)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
// Clean the path and redirect to the naked URL.
|
||||
// This is intended to prevent leaking potentially
|
||||
// sensitive query parameters for authentication
|
||||
// methods.
|
||||
http.Redirect(w, r, r.URL.Path, http.StatusFound)
|
||||
return
|
||||
}
|
||||
methods[s.Type()] = promptData
|
||||
methods[s.Type().String()] = promptData
|
||||
}
|
||||
|
||||
// The handler is passed through the scheme middlewares,
|
||||
// if none of them intercept the request, then this handler will
|
||||
// be called and present the user with the authentication page.
|
||||
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if err := tmpl.Execute(w, methods); err != nil {
|
||||
if err := tmpl.Execute(w, struct {
|
||||
Methods map[string]string
|
||||
}{
|
||||
Methods: methods,
|
||||
}); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadGateway)
|
||||
}
|
||||
}))
|
||||
|
||||
@@ -83,18 +83,18 @@ func (*OIDC) Type() Method {
|
||||
return MethodOIDC
|
||||
}
|
||||
|
||||
func (o *OIDC) Authenticate(r *http.Request) (string, bool, any) {
|
||||
func (o *OIDC) Authenticate(r *http.Request) (string, string) {
|
||||
// Try Authorization: Bearer <token> header
|
||||
if auth := r.Header.Get("Authorization"); strings.HasPrefix(auth, "Bearer ") {
|
||||
if userID := o.validateToken(r.Context(), strings.TrimPrefix(auth, "Bearer ")); userID != "" {
|
||||
return userID, false, nil
|
||||
return userID, ""
|
||||
}
|
||||
}
|
||||
|
||||
// Try _auth_token query parameter (from OIDC callback redirect)
|
||||
if token := r.URL.Query().Get("_auth_token"); token != "" {
|
||||
if userID := o.validateToken(r.Context(), token); userID != "" {
|
||||
return userID, true, nil // Redirect needed to clean up URL
|
||||
return userID, ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ func (o *OIDC) Authenticate(r *http.Request) (string, bool, any) {
|
||||
o.states[state] = &oidcState{OriginalURL: fmt.Sprintf("https://%s%s", r.Host, r.URL), CreatedAt: time.Now()}
|
||||
o.statesMux.Unlock()
|
||||
|
||||
return "", false, o.oauthConfig.AuthCodeURL(state)
|
||||
return "", o.oauthConfig.AuthCodeURL(state)
|
||||
}
|
||||
|
||||
// Middleware returns an http.Handler that handles OIDC callback and flow initiation.
|
||||
|
||||
@@ -33,7 +33,7 @@ func (Password) Type() Method {
|
||||
// If authentication fails, the required HTTP form ID is returned
|
||||
// so that it can be injected into a request from the UI so that
|
||||
// authentication may be successful.
|
||||
func (p Password) Authenticate(r *http.Request) (string, bool, any) {
|
||||
func (p Password) Authenticate(r *http.Request) (string, string) {
|
||||
password := r.FormValue(passwordFormId)
|
||||
|
||||
res, err := p.client.Authenticate(r.Context(), &proto.AuthenticateRequest{
|
||||
@@ -47,14 +47,14 @@ func (p Password) Authenticate(r *http.Request) (string, bool, any) {
|
||||
})
|
||||
if err != nil {
|
||||
// TODO: log error here
|
||||
return "", false, passwordFormId
|
||||
return "", passwordFormId
|
||||
}
|
||||
|
||||
if res.GetSuccess() {
|
||||
return passwordUserId, true, nil
|
||||
return passwordUserId, ""
|
||||
}
|
||||
|
||||
return "", false, passwordFormId
|
||||
return "", passwordFormId
|
||||
}
|
||||
|
||||
func (p Password) Middleware(next http.Handler) http.Handler {
|
||||
|
||||
@@ -33,7 +33,7 @@ func (Pin) Type() Method {
|
||||
// If authentication fails, the required HTTP form ID is returned
|
||||
// so that it can be injected into a request from the UI so that
|
||||
// authentication may be successful.
|
||||
func (p Pin) Authenticate(r *http.Request) (string, bool, any) {
|
||||
func (p Pin) Authenticate(r *http.Request) (string, string) {
|
||||
pin := r.FormValue(pinFormId)
|
||||
|
||||
res, err := p.client.Authenticate(r.Context(), &proto.AuthenticateRequest{
|
||||
@@ -47,14 +47,14 @@ func (p Pin) Authenticate(r *http.Request) (string, bool, any) {
|
||||
})
|
||||
if err != nil {
|
||||
// TODO: log error here
|
||||
return "", false, pinFormId
|
||||
return "", pinFormId
|
||||
}
|
||||
|
||||
if res.GetSuccess() {
|
||||
return pinUserId, true, nil
|
||||
return pinUserId, ""
|
||||
}
|
||||
|
||||
return "", false, pinFormId
|
||||
return "", pinFormId
|
||||
}
|
||||
|
||||
func (p Pin) Middleware(next http.Handler) http.Handler {
|
||||
|
||||
Reference in New Issue
Block a user