mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-01 10:40:30 -05:00
252 lines
6.3 KiB
Go
252 lines
6.3 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 identifier
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/golang-jwt/jwt/v5"
|
|
|
|
konnect "github.com/libregraph/lico"
|
|
"github.com/libregraph/lico/identifier/backends"
|
|
"github.com/libregraph/lico/identity"
|
|
"github.com/libregraph/lico/identity/authorities"
|
|
)
|
|
|
|
// A IdentifiedUser is a user with meta data.
|
|
type IdentifiedUser struct {
|
|
sub string
|
|
|
|
backend backends.Backend
|
|
externalAuthority *authorities.Details
|
|
|
|
username string
|
|
email string
|
|
emailVerified bool
|
|
displayName string
|
|
familyName string
|
|
givenName string
|
|
|
|
id int64
|
|
uid string
|
|
|
|
sessionRef *string
|
|
logonRef *string
|
|
claims map[string]interface{}
|
|
scopes []string
|
|
|
|
logonAt time.Time
|
|
expiresAfter *time.Time
|
|
|
|
lockedScopes []string
|
|
}
|
|
|
|
// Subject returns the associated users subject field. The subject is the main
|
|
// authentication identifier of the user.
|
|
func (u *IdentifiedUser) Subject() string {
|
|
return u.sub
|
|
}
|
|
|
|
// Email returns the associated users email field.
|
|
func (u *IdentifiedUser) Email() string {
|
|
return u.email
|
|
}
|
|
|
|
// EmailVerified returns trye if the associated users email field was verified.
|
|
func (u *IdentifiedUser) EmailVerified() bool {
|
|
return u.emailVerified
|
|
}
|
|
|
|
// Name returns the associated users name field. This is the display name of
|
|
// the accociated user.
|
|
func (u *IdentifiedUser) Name() string {
|
|
return u.displayName
|
|
}
|
|
|
|
// FamilyName returns the associated users family name field.
|
|
func (u *IdentifiedUser) FamilyName() string {
|
|
return u.familyName
|
|
}
|
|
|
|
// GivenName returns the associated users given name field.
|
|
func (u *IdentifiedUser) GivenName() string {
|
|
return u.givenName
|
|
}
|
|
|
|
// ID returns the associated users numeric user id. If it is 0, it means that
|
|
// this user does not have a numeric ID. Do not use this field to identify a
|
|
// user - always use the subject instead. The numeric ID is kept for compatibility
|
|
// with systems which require user identification to be numeric.
|
|
func (u *IdentifiedUser) ID() int64 {
|
|
return u.id
|
|
}
|
|
|
|
// UniqueID returns the accociated users unique user id. When empty, then this
|
|
// user does not have a unique ID. This field can be used for unique user mapping
|
|
// to external systems which use the same authentication source as Konnect. The
|
|
// value depends entirely on the identifier backend.
|
|
func (u *IdentifiedUser) UniqueID() string {
|
|
return u.uid
|
|
}
|
|
|
|
// Username returns the accociated users username. This might be different or
|
|
// the same as the subject, depending on the backend in use. If can also be
|
|
// empty, which means that the accociated user does not have a username.
|
|
func (u *IdentifiedUser) Username() string {
|
|
return u.username
|
|
}
|
|
|
|
// Claims returns extra claims of the accociated user.
|
|
func (u *IdentifiedUser) Claims() jwt.MapClaims {
|
|
claims := make(map[string]interface{})
|
|
claims[konnect.IdentifiedUsernameClaim] = u.Username()
|
|
claims[konnect.IdentifiedDisplayNameClaim] = u.Name()
|
|
|
|
for k, v := range u.claims {
|
|
claims[k] = v
|
|
}
|
|
|
|
return jwt.MapClaims(claims)
|
|
}
|
|
|
|
// ScopedClaims returns scope bound extra claims of the accociated user.
|
|
func (u *IdentifiedUser) ScopedClaims(authorizedScopes map[string]bool) jwt.MapClaims {
|
|
if u.backend == nil {
|
|
return nil
|
|
}
|
|
|
|
claims := u.backend.UserClaims(u.Subject(), authorizedScopes)
|
|
return jwt.MapClaims(claims)
|
|
}
|
|
|
|
// Scopes returns the scopes attached to this user.
|
|
func (u *IdentifiedUser) Scopes() []string {
|
|
return u.scopes
|
|
}
|
|
|
|
// LoggedOn returns true if the accociated user has a logonAt time set.
|
|
func (u *IdentifiedUser) LoggedOn() (bool, time.Time) {
|
|
return !u.logonAt.IsZero(), u.logonAt
|
|
}
|
|
|
|
// SessionRef returns the accociated users underlaying session reference.
|
|
func (u *IdentifiedUser) SessionRef() *string {
|
|
return u.sessionRef
|
|
}
|
|
|
|
// UserRef returns the accociated users underlaying logon reference.
|
|
func (u *IdentifiedUser) LogonRef() *string {
|
|
return u.logonRef
|
|
}
|
|
|
|
func (u *IdentifiedUser) ExternalAuthorityID() *string {
|
|
if u.externalAuthority == nil {
|
|
return nil
|
|
}
|
|
id := u.externalAuthority.ID
|
|
return &id
|
|
}
|
|
|
|
// BackendName returns the accociated users underlaying backend name.
|
|
func (u *IdentifiedUser) BackendName() string {
|
|
return u.backend.Name()
|
|
}
|
|
|
|
func (u *IdentifiedUser) LockedScopes() []string {
|
|
return u.lockedScopes
|
|
}
|
|
|
|
func (i *Identifier) logonUser(ctx context.Context, audience, username, password string) (*IdentifiedUser, error) {
|
|
success, subject, sessionRef, u, err := i.backend.Logon(ctx, audience, username, password)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if !success || u == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
user := &IdentifiedUser{
|
|
sub: *subject,
|
|
|
|
username: u.Username(),
|
|
|
|
backend: i.backend,
|
|
|
|
sessionRef: sessionRef,
|
|
claims: u.BackendClaims(),
|
|
|
|
lockedScopes: u.RequiredScopes(),
|
|
}
|
|
|
|
return user, nil
|
|
}
|
|
|
|
func (i *Identifier) resolveUser(ctx context.Context, username string) (*IdentifiedUser, error) {
|
|
u, err := i.backend.ResolveUserByUsername(ctx, username)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if u == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
// Construct user from resolved result.
|
|
user := &IdentifiedUser{
|
|
sub: u.Subject(),
|
|
|
|
username: u.Username(),
|
|
|
|
backend: i.backend,
|
|
|
|
claims: u.BackendClaims(),
|
|
|
|
lockedScopes: u.RequiredScopes(),
|
|
}
|
|
|
|
return user, nil
|
|
}
|
|
|
|
func (i *Identifier) updateUser(ctx context.Context, user *IdentifiedUser, externalAuthority *authorities.Details) error {
|
|
var userID string
|
|
identityClaims := user.Claims()
|
|
if userIDString, ok := identityClaims[konnect.IdentifiedUserIDClaim]; ok {
|
|
userID = userIDString.(string)
|
|
}
|
|
if userID == "" {
|
|
return errors.New("no id claim in user identity claims")
|
|
}
|
|
|
|
u, err := i.backend.GetUser(ctx, userID, user.sessionRef, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if uwp, ok := u.(identity.UserWithProfile); ok {
|
|
user.displayName = uwp.Name()
|
|
}
|
|
|
|
user.backend = i.backend
|
|
user.externalAuthority = externalAuthority
|
|
|
|
return nil
|
|
}
|