2023-01-23 07:11:40 +00:00
|
|
|
package oidc
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
|
|
|
|
2023-10-17 15:19:51 +00:00
|
|
|
"github.com/zitadel/oidc/v3/pkg/client/rp"
|
|
|
|
"github.com/zitadel/oidc/v3/pkg/oidc"
|
2023-01-23 07:11:40 +00:00
|
|
|
"golang.org/x/text/language"
|
|
|
|
|
2023-03-14 19:20:38 +00:00
|
|
|
"github.com/zitadel/zitadel/internal/domain"
|
2023-01-23 07:11:40 +00:00
|
|
|
"github.com/zitadel/zitadel/internal/idp"
|
|
|
|
)
|
|
|
|
|
|
|
|
var ErrCodeMissing = errors.New("no auth code provided")
|
|
|
|
|
|
|
|
var _ idp.Session = (*Session)(nil)
|
|
|
|
|
|
|
|
// Session is the [idp.Session] implementation for the OIDC provider.
|
|
|
|
type Session struct {
|
|
|
|
Provider *Provider
|
|
|
|
AuthURL string
|
|
|
|
Code string
|
2023-03-28 11:28:56 +00:00
|
|
|
Tokens *oidc.Tokens[*oidc.IDTokenClaims]
|
2023-01-23 07:11:40 +00:00
|
|
|
}
|
|
|
|
|
2023-09-29 09:26:14 +00:00
|
|
|
// GetAuth implements the [idp.Session] interface.
|
|
|
|
func (s *Session) GetAuth(ctx context.Context) (string, bool) {
|
|
|
|
return idp.Redirect(s.AuthURL)
|
2023-01-23 07:11:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// FetchUser implements the [idp.Session] interface.
|
|
|
|
// It will execute an OIDC code exchange if needed to retrieve the tokens,
|
|
|
|
// call the userinfo endpoint and map the received information into an [idp.User].
|
|
|
|
func (s *Session) FetchUser(ctx context.Context) (user idp.User, err error) {
|
|
|
|
if s.Tokens == nil {
|
2023-08-31 06:39:16 +00:00
|
|
|
if err = s.Authorize(ctx); err != nil {
|
2023-01-23 07:11:40 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
2023-10-17 15:19:51 +00:00
|
|
|
info, err := rp.Userinfo[*oidc.UserInfo](ctx,
|
2023-01-23 07:11:40 +00:00
|
|
|
s.Tokens.AccessToken,
|
|
|
|
s.Tokens.TokenType,
|
|
|
|
s.Tokens.IDTokenClaims.GetSubject(),
|
|
|
|
s.Provider.RelyingParty,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-03-16 15:47:22 +00:00
|
|
|
if s.Provider.useIDToken {
|
2023-03-28 11:28:56 +00:00
|
|
|
info = s.Tokens.IDTokenClaims.GetUserInfo()
|
2023-03-16 15:47:22 +00:00
|
|
|
}
|
2023-01-23 07:11:40 +00:00
|
|
|
u := s.Provider.userInfoMapper(info)
|
|
|
|
return u, nil
|
|
|
|
}
|
|
|
|
|
2023-08-31 06:39:16 +00:00
|
|
|
func (s *Session) Authorize(ctx context.Context) (err error) {
|
2023-01-23 07:11:40 +00:00
|
|
|
if s.Code == "" {
|
|
|
|
return ErrCodeMissing
|
|
|
|
}
|
2023-03-28 11:28:56 +00:00
|
|
|
s.Tokens, err = rp.CodeExchange[*oidc.IDTokenClaims](ctx, s.Code, s.Provider.RelyingParty)
|
2023-01-23 07:11:40 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-03-28 11:28:56 +00:00
|
|
|
func NewUser(info *oidc.UserInfo) *User {
|
2023-01-23 07:11:40 +00:00
|
|
|
return &User{UserInfo: info}
|
|
|
|
}
|
|
|
|
|
|
|
|
type User struct {
|
2023-03-28 11:28:56 +00:00
|
|
|
*oidc.UserInfo
|
2023-01-23 07:11:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (u *User) GetID() string {
|
2023-03-28 11:28:56 +00:00
|
|
|
return u.Subject
|
2023-01-23 07:11:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (u *User) GetFirstName() string {
|
2023-03-28 11:28:56 +00:00
|
|
|
return u.GivenName
|
2023-01-23 07:11:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (u *User) GetLastName() string {
|
2023-03-28 11:28:56 +00:00
|
|
|
return u.FamilyName
|
2023-01-23 07:11:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (u *User) GetDisplayName() string {
|
2023-03-28 11:28:56 +00:00
|
|
|
return u.Name
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *User) GetNickname() string {
|
|
|
|
return u.Nickname
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *User) GetPreferredUsername() string {
|
|
|
|
return u.PreferredUsername
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *User) GetEmail() domain.EmailAddress {
|
|
|
|
return domain.EmailAddress(u.UserInfo.Email)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *User) IsEmailVerified() bool {
|
|
|
|
return bool(u.EmailVerified)
|
2023-01-23 07:11:40 +00:00
|
|
|
}
|
|
|
|
|
2023-03-14 19:20:38 +00:00
|
|
|
func (u *User) GetPhone() domain.PhoneNumber {
|
2023-03-28 11:28:56 +00:00
|
|
|
return domain.PhoneNumber(u.PhoneNumber)
|
2023-01-23 07:11:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (u *User) IsPhoneVerified() bool {
|
2023-03-28 11:28:56 +00:00
|
|
|
return u.PhoneNumberVerified
|
2023-01-23 07:11:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (u *User) GetPreferredLanguage() language.Tag {
|
2023-03-28 11:28:56 +00:00
|
|
|
return u.Locale.Tag()
|
2023-01-23 07:11:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (u *User) GetAvatarURL() string {
|
2023-03-28 11:28:56 +00:00
|
|
|
return u.Picture
|
2023-01-23 07:11:40 +00:00
|
|
|
}
|
2023-03-14 19:20:38 +00:00
|
|
|
|
2023-03-28 11:28:56 +00:00
|
|
|
func (u *User) GetProfile() string {
|
|
|
|
return u.Profile
|
2023-03-14 19:20:38 +00:00
|
|
|
}
|