Files
opencloud/vendor/github.com/libregraph/lico/identity/managers/dummy.go
Christian Richter 16307e036d add new property IdentifierDefaultLogoTargetURI
Signed-off-by: Christian Richter <c.richter@opencloud.eu>
2025-04-28 13:36:13 +02:00

229 lines
6.7 KiB
Go

/*
* Copyright 2017-2019 Kopano and its licensors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package managers
import (
"context"
"fmt"
"net/http"
"strings"
"github.com/golang-jwt/jwt/v5"
"github.com/gorilla/mux"
"github.com/libregraph/oidc-go"
"github.com/longsleep/rndm"
konnect "github.com/libregraph/lico"
"github.com/libregraph/lico/identity"
"github.com/libregraph/lico/oidc/payload"
)
const dummyIdentityManagerName = "dummy"
// DummyIdentityManager implements an identity manager which always grants
// access to a fixed user id.
type DummyIdentityManager struct {
sub string
scopesSupported []string
}
// NewDummyIdentityManager creates a new DummyIdentityManager from the
// provided parameters.
func NewDummyIdentityManager(c *identity.Config, sub string) *DummyIdentityManager {
im := &DummyIdentityManager{
sub: sub,
scopesSupported: setupSupportedScopes([]string{
oidc.ScopeProfile,
oidc.ScopeEmail,
}, nil, c.ScopesSupported),
}
return im
}
type dummyUser struct {
raw string
}
func (u *dummyUser) Raw() string {
return u.raw
}
func (u *dummyUser) Subject() string {
sub, _ := getPublicSubject([]byte(u.raw), []byte(dummyIdentityManagerName))
return sub
}
func (u *dummyUser) Email() string {
return fmt.Sprintf("%s@%s.local", u.raw, u.raw)
}
func (u *dummyUser) EmailVerified() bool {
return false
}
func (u *dummyUser) Name() string {
return fmt.Sprintf("Foo %s", strings.Title(u.raw))
}
func (u *dummyUser) Claims() jwt.MapClaims {
claims := make(jwt.MapClaims)
claims[konnect.IdentifiedUserIDClaim] = u.raw
return claims
}
// Authenticate implements the identity.Manager interface.
func (im *DummyIdentityManager) Authenticate(ctx context.Context, rw http.ResponseWriter, req *http.Request, ar *payload.AuthenticationRequest, next identity.Manager) (identity.AuthRecord, error) {
user := &dummyUser{im.sub}
// Check request.
err := ar.Verify(user.Subject())
if err != nil {
return nil, err
}
auth := identity.NewAuthRecord(im, user.Subject(), nil, nil, nil)
auth.SetUser(user)
return auth, nil
}
// Authorize implements the identity.Manager interface.
func (im *DummyIdentityManager) Authorize(ctx context.Context, rw http.ResponseWriter, req *http.Request, ar *payload.AuthenticationRequest, auth identity.AuthRecord) (identity.AuthRecord, error) {
promptConsent := false
var approvedScopes map[string]bool
// Check prompt value.
switch {
case ar.Prompts[oidc.PromptConsent] == true:
promptConsent = true
default:
// Let all other prompt values pass.
}
// TODO(longsleep): Move the code below to general function.
// TODO(longsleep): Validate scopes and force prompt.
approvedScopes = ar.Scopes
// Offline access validation.
// http://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess
if ok, _ := ar.Scopes[oidc.ScopeOfflineAccess]; ok {
if !promptConsent {
// Ensure that the prompt parameter contains consent unless
// other conditions for processing the request permitting offline
// access to the requested resources are in place; unless one or
// both of these conditions are fulfilled, then it MUST ignore the
// offline_access request,
delete(ar.Scopes, oidc.ScopeOfflineAccess)
}
}
if promptConsent {
if ar.Prompts[oidc.PromptNone] == true {
return auth, ar.NewError(oidc.ErrorCodeOIDCInteractionRequired, "consent required")
}
// TODO(longsleep): Implement consent page.
return auth, ar.NewError(oidc.ErrorCodeOIDCInteractionRequired, "consent required, but page not implemented")
}
auth.AuthorizeScopes(approvedScopes)
auth.AuthorizeClaims(ar.Claims)
return auth, nil
}
// EndSession implements the identity.Manager interface.
func (im *DummyIdentityManager) EndSession(ctx context.Context, rw http.ResponseWriter, req *http.Request, esr *payload.EndSessionRequest) error {
user := &dummyUser{im.sub}
err := esr.Verify(user.Subject())
if err != nil {
return err
}
return nil
}
// ApproveScopes implements the Backend interface.
func (im *DummyIdentityManager) ApproveScopes(ctx context.Context, sub string, audience string, approvedScopes map[string]bool) (string, error) {
ref := rndm.GenerateRandomString(32)
// TODO(longsleep): Store generated ref with provided data.
return ref, nil
}
// ApprovedScopes implements the Backend interface.
func (im *DummyIdentityManager) ApprovedScopes(ctx context.Context, sub string, audience string, ref string) (map[string]bool, error) {
if ref == "" {
return nil, fmt.Errorf("SimplePasswdBackend: invalid ref")
}
return nil, nil
}
// Fetch implements the identity.Manager interface.
func (im *DummyIdentityManager) Fetch(ctx context.Context, userID string, sessionRef *string, scopes map[string]bool, requestedClaimsMaps []*payload.ClaimsRequestMap, requestedScopes map[string]bool) (identity.AuthRecord, bool, error) {
if userID != im.sub {
return nil, false, fmt.Errorf("DummyIdentityManager: no user")
}
user := &dummyUser{im.sub}
authorizedScopes, _ := identity.AuthorizeScopes(im, user, scopes)
claims := identity.GetUserClaimsForScopes(user, authorizedScopes, requestedClaimsMaps)
return identity.NewAuthRecord(im, user.Subject(), authorizedScopes, nil, claims), true, nil
}
// Name implements the identity.Manager interface.
func (im *DummyIdentityManager) Name() string {
return dummyIdentityManagerName
}
// ScopesSupported implements the identity.Manager interface.
func (im *DummyIdentityManager) ScopesSupported(scopes map[string]bool) []string {
return im.scopesSupported
}
// ClaimsSupported implements the identity.Manager interface.
func (im *DummyIdentityManager) ClaimsSupported(claims []string) []string {
return []string{
oidc.NameClaim,
oidc.EmailClaim,
oidc.EmailVerifiedClaim,
}
}
// AddRoutes implements the identity.Manager interface.
func (im *DummyIdentityManager) AddRoutes(ctx context.Context, router *mux.Router) {
}
// OnSetLogon implements the identity.Manager interface.
func (im *DummyIdentityManager) OnSetLogon(func(ctx context.Context, rw http.ResponseWriter, user identity.User) error) error {
return nil
}
// OnUnsetLogon implements the identity.Manager interface.
func (im *DummyIdentityManager) OnUnsetLogon(func(ctx context.Context, rw http.ResponseWriter) error) error {
return nil
}