diff --git a/routers/api/packages/chef/auth.go b/routers/api/packages/chef/auth.go index a790e9a363..8ed4f03993 100644 --- a/routers/api/packages/chef/auth.go +++ b/routers/api/packages/chef/auth.go @@ -52,6 +52,10 @@ func (a *Auth) Name() string { return "chef" } +func (a *Auth) Match(req *http.Request) bool { + return true +} + // Verify extracts the user from the signed request // If the request is signed with the user private key the user is verified. func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataStore, sess auth.SessionStore) (*user_model.User, error) { diff --git a/routers/api/packages/conan/auth.go b/routers/api/packages/conan/auth.go index 9c03d01391..7a7703c5d8 100644 --- a/routers/api/packages/conan/auth.go +++ b/routers/api/packages/conan/auth.go @@ -20,6 +20,10 @@ func (a *Auth) Name() string { return "conan" } +func (a *Auth) Match(req *http.Request) bool { + return true +} + // Verify extracts the user from the Bearer token func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataStore, sess auth.SessionStore) (*user_model.User, error) { packageMeta, err := packages.ParseAuthorizationRequest(req) diff --git a/routers/api/packages/container/auth.go b/routers/api/packages/container/auth.go index 1d8ae6af7d..01f273ddf6 100644 --- a/routers/api/packages/container/auth.go +++ b/routers/api/packages/container/auth.go @@ -20,6 +20,10 @@ func (a *Auth) Name() string { return "container" } +func (a *Auth) Match(req *http.Request) bool { + return true +} + // Verify extracts the user from the Bearer token // If it's an anonymous session a ghost user is returned func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataStore, sess auth.SessionStore) (*user_model.User, error) { diff --git a/routers/api/packages/nuget/auth.go b/routers/api/packages/nuget/auth.go index e81ad01b2b..20dff9c46c 100644 --- a/routers/api/packages/nuget/auth.go +++ b/routers/api/packages/nuget/auth.go @@ -21,6 +21,10 @@ func (a *Auth) Name() string { return "nuget" } +func (a *Auth) Match(req *http.Request) bool { + return true +} + // https://docs.microsoft.com/en-us/nuget/api/package-publish-resource#request-parameters func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataStore, sess auth.SessionStore) (*user_model.User, error) { token, err := auth_model.GetAccessTokenBySHA(req.Context(), req.Header.Get("X-NuGet-ApiKey")) diff --git a/services/auth/basic.go b/services/auth/basic.go index 90bd642370..02526678ea 100644 --- a/services/auth/basic.go +++ b/services/auth/basic.go @@ -42,6 +42,10 @@ func (b *Basic) Name() string { return BasicMethodName } +func (b *Basic) Match(req *http.Request) bool { + return true +} + // Verify extracts and validates Basic data (username and password/token) from the // "Authorization" header of the request and returns the corresponding user object for that // name/token on successful validation. diff --git a/services/auth/group.go b/services/auth/group.go index aecf43cb24..b9339dc80a 100644 --- a/services/auth/group.go +++ b/services/auth/group.go @@ -41,10 +41,22 @@ func (b *Group) Name() string { return strings.Join(names, ",") } +func (b *Group) Match(req *http.Request) bool { + return true +} + func (b *Group) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) { - // Try to sign in with each of the enabled plugins - var retErr error + // find all methods that match the request + matchedMethods := make([]Method, 0, len(b.methods)) for _, m := range b.methods { + if m.Match(req) { + matchedMethods = append(matchedMethods, m) + } + } + + var retErr error + // Try to sign in with each of the matched plugins + for _, m := range matchedMethods { user, err := m.Verify(req, w, store, sess) if err != nil { if retErr == nil { diff --git a/services/auth/httpsign.go b/services/auth/httpsign.go index 83a36bef23..9a8b9d77cc 100644 --- a/services/auth/httpsign.go +++ b/services/auth/httpsign.go @@ -36,6 +36,10 @@ func (h *HTTPSign) Name() string { return "httpsign" } +func (h *HTTPSign) Match(req *http.Request) bool { + return true +} + // Verify extracts and validates HTTPsign from the Signature header of the request and returns // the corresponding user object on successful validation. // Returns nil if header is empty or validation fails. diff --git a/services/auth/interface.go b/services/auth/interface.go index ece28af12d..f2e6fceeb3 100644 --- a/services/auth/interface.go +++ b/services/auth/interface.go @@ -24,10 +24,12 @@ type Method interface { // If verification is successful returns either an existing user object (with id > 0) // or a new user object (with id = 0) populated with the information that was found // in the authentication data (username or email). - // Second argument returns err if verification fails, otherwise + // Third argument returns err if verification fails, otherwise + // Second return argument returns true // First return argument returns nil if no matched verification condition Verify(http *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) - + // Match returns true if the request is a match for this method + Match(*http.Request) bool Name() string } diff --git a/services/auth/oauth2.go b/services/auth/oauth2.go index d0aec085b1..089bbc44f2 100644 --- a/services/auth/oauth2.go +++ b/services/auth/oauth2.go @@ -131,6 +131,10 @@ func (o *OAuth2) userIDFromToken(ctx context.Context, tokenSHA string, store Dat return t.UID } +func (o *OAuth2) Match(req *http.Request) bool { + return true +} + // Verify extracts the user ID from the OAuth token in the query parameters // or the "Authorization" header and returns the corresponding user object for that ID. // If verification is successful returns an existing user object. diff --git a/services/auth/reverseproxy.go b/services/auth/reverseproxy.go index 36b4ef68f4..4479fa60f1 100644 --- a/services/auth/reverseproxy.go +++ b/services/auth/reverseproxy.go @@ -100,6 +100,10 @@ func (r *ReverseProxy) getUserFromAuthEmail(req *http.Request) *user_model.User return user } +func (r *ReverseProxy) Match(req *http.Request) bool { + return true +} + // Verify attempts to load a user object based on headers sent by the reverse proxy. // First it will attempt to load it based on the username (see docs for getUserFromAuthUser), // and failing that it will attempt to load it based on the email (see docs for getUserFromAuthEmail). diff --git a/services/auth/session.go b/services/auth/session.go index 35d97e42da..98d8d11ca8 100644 --- a/services/auth/session.go +++ b/services/auth/session.go @@ -24,6 +24,10 @@ func (s *Session) Name() string { return "session" } +func (s *Session) Match(req *http.Request) bool { + return true +} + // Verify checks if there is a user uid stored in the session and returns the user // object for that uid. // Returns nil if there is no user uid stored in the session. diff --git a/services/auth/sspi.go b/services/auth/sspi.go index 7f8a03a4c6..648fbc617b 100644 --- a/services/auth/sspi.go +++ b/services/auth/sspi.go @@ -54,6 +54,10 @@ func (s *SSPI) Name() string { return "sspi" } +func (s *SSPI) Match(req *http.Request) bool { + return true +} + // Verify uses SSPI (Windows implementation of SPNEGO) to authenticate the request. // If authentication is successful, returns the corresponding user object. // If negotiation should continue or authentication fails, immediately returns a 401 HTTP