mirror of
https://github.com/project-zot/zot.git
synced 2026-06-17 04:48:26 +08:00
feat: integrate openID auth logic and user profile management (#1381)
This change introduces OpenID authn by using providers such as Github, Gitlab, Google and Dex. User sessions are now used for web clients to identify and persist an authenticated users session, thus not requiring every request to use credentials. Another change is apikey feature, users can create/revoke their api keys and use them to authenticate when using cli clients such as skopeo. eg: login: /auth/login?provider=github /auth/login?provider=gitlab and so on logout: /auth/logout redirectURL: /auth/callback/github /auth/callback/gitlab and so on If network policy doesn't allow inbound connections, this callback wont work! for more info read documentation added in this commit. Signed-off-by: Alex Stan <alexandrustan96@yahoo.ro> Signed-off-by: Petu Eusebiu <peusebiu@cisco.com> Co-authored-by: Alex Stan <alexandrustan96@yahoo.ro>
This commit is contained in:
@@ -15,6 +15,7 @@ import (
|
||||
"log"
|
||||
"math"
|
||||
"math/big"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -38,6 +39,7 @@ import (
|
||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/opencontainers/umoci"
|
||||
"github.com/phayes/freeport"
|
||||
"github.com/project-zot/mockoidc"
|
||||
"github.com/sigstore/cosign/v2/cmd/cosign/cli/generate"
|
||||
"github.com/sigstore/cosign/v2/cmd/cosign/cli/options"
|
||||
"github.com/sigstore/cosign/v2/cmd/cosign/cli/sign"
|
||||
@@ -1967,3 +1969,55 @@ func GetIndexBlobWithManifests(manifestDigests []godigest.Digest) ([]byte, error
|
||||
|
||||
return json.Marshal(indexContent)
|
||||
}
|
||||
|
||||
func MockOIDCRun() (*mockoidc.MockOIDC, error) {
|
||||
// Create a fresh RSA Private Key for token signing
|
||||
rsaKey, _ := rsa.GenerateKey(rand.Reader, 2048) //nolint: gomnd
|
||||
|
||||
// Create an unstarted MockOIDC server
|
||||
mockServer, _ := mockoidc.NewServer(rsaKey)
|
||||
|
||||
// Create the net.Listener, kernel will chose a valid port
|
||||
listener, _ := net.Listen("tcp", "127.0.0.1:0")
|
||||
|
||||
bearerMiddleware := func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(response http.ResponseWriter, req *http.Request) {
|
||||
// stateVal := req.Form.Get("state")
|
||||
header := req.Header.Get("Authorization")
|
||||
parts := strings.SplitN(header, " ", 2) //nolint: gomnd
|
||||
if header != "" {
|
||||
if strings.ToLower(parts[0]) == "bearer" {
|
||||
req.Header.Set("Authorization", strings.Join([]string{"Bearer", parts[1]}, " "))
|
||||
}
|
||||
}
|
||||
|
||||
next.ServeHTTP(response, req)
|
||||
})
|
||||
}
|
||||
|
||||
err := mockServer.AddMiddleware(bearerMiddleware)
|
||||
if err != nil {
|
||||
return mockServer, err
|
||||
}
|
||||
// tlsConfig can be nil if you want HTTP
|
||||
return mockServer, mockServer.Start(listener, nil)
|
||||
}
|
||||
|
||||
func CustomRedirectPolicy(noOfRedirect int) resty.RedirectPolicy {
|
||||
return resty.RedirectPolicyFunc(func(req *http.Request, via []*http.Request) error {
|
||||
if len(via) >= noOfRedirect {
|
||||
return fmt.Errorf("stopped after %d redirects", noOfRedirect) //nolint: goerr113
|
||||
}
|
||||
|
||||
for key, val := range via[len(via)-1].Header {
|
||||
req.Header[key] = val
|
||||
}
|
||||
|
||||
respCookies := req.Response.Cookies()
|
||||
for _, cookie := range respCookies {
|
||||
req.AddCookie(cookie)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -95,6 +95,24 @@ type RepoDBMock struct {
|
||||
|
||||
ToggleBookmarkRepoFn func(ctx context.Context, repo string) (repodb.ToggleState, error)
|
||||
|
||||
GetUserDataFn func(ctx context.Context) (repodb.UserData, error)
|
||||
|
||||
SetUserDataFn func(ctx context.Context, userProfile repodb.UserData) error
|
||||
|
||||
SetUserGroupsFn func(ctx context.Context, groups []string) error
|
||||
|
||||
GetUserGroupsFn func(ctx context.Context) ([]string, error)
|
||||
|
||||
DeleteUserDataFn func(ctx context.Context) error
|
||||
|
||||
GetUserAPIKeyInfoFn func(hashedKey string) (string, error)
|
||||
|
||||
AddUserAPIKeyFn func(ctx context.Context, hashedKey string, apiKeyDetails *repodb.APIKeyDetails) error
|
||||
|
||||
UpdateUserAPIKeyLastUsedFn func(ctx context.Context, hashedKey string) error
|
||||
|
||||
DeleteUserAPIKeyFn func(ctx context.Context, id string) error
|
||||
|
||||
PatchDBFn func() error
|
||||
}
|
||||
|
||||
@@ -414,3 +432,75 @@ func (sdm RepoDBMock) ToggleBookmarkRepo(ctx context.Context, repo string) (repo
|
||||
|
||||
return repodb.NotChanged, nil
|
||||
}
|
||||
|
||||
func (sdm RepoDBMock) GetUserData(ctx context.Context) (repodb.UserData, error) {
|
||||
if sdm.GetUserDataFn != nil {
|
||||
return sdm.GetUserDataFn(ctx)
|
||||
}
|
||||
|
||||
return repodb.UserData{}, nil
|
||||
}
|
||||
|
||||
func (sdm RepoDBMock) SetUserData(ctx context.Context, userProfile repodb.UserData) error {
|
||||
if sdm.SetUserDataFn != nil {
|
||||
return sdm.SetUserDataFn(ctx, userProfile)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sdm RepoDBMock) SetUserGroups(ctx context.Context, groups []string) error {
|
||||
if sdm.SetUserGroupsFn != nil {
|
||||
return sdm.SetUserGroupsFn(ctx, groups)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sdm RepoDBMock) GetUserGroups(ctx context.Context) ([]string, error) {
|
||||
if sdm.GetUserGroupsFn != nil {
|
||||
return sdm.GetUserGroupsFn(ctx)
|
||||
}
|
||||
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
func (sdm RepoDBMock) DeleteUserData(ctx context.Context) error {
|
||||
if sdm.DeleteUserDataFn != nil {
|
||||
return sdm.DeleteUserDataFn(ctx)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sdm RepoDBMock) GetUserAPIKeyInfo(hashedKey string) (string, error) {
|
||||
if sdm.GetUserAPIKeyInfoFn != nil {
|
||||
return sdm.GetUserAPIKeyInfoFn(hashedKey)
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (sdm RepoDBMock) AddUserAPIKey(ctx context.Context, hashedKey string, apiKeyDetails *repodb.APIKeyDetails) error {
|
||||
if sdm.AddUserAPIKeyFn != nil {
|
||||
return sdm.AddUserAPIKeyFn(ctx, hashedKey, apiKeyDetails)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sdm RepoDBMock) UpdateUserAPIKeyLastUsed(ctx context.Context, hashedKey string) error {
|
||||
if sdm.UpdateUserAPIKeyLastUsedFn != nil {
|
||||
return sdm.UpdateUserAPIKeyLastUsedFn(ctx, hashedKey)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sdm RepoDBMock) DeleteUserAPIKey(ctx context.Context, id string) error {
|
||||
if sdm.DeleteUserAPIKeyFn != nil {
|
||||
return sdm.DeleteUserAPIKeyFn(ctx, id)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user