mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 01:47:33 +00:00
feat: add auth command side (#107)
* fix: query tests * fix: use prepare funcs * fix: go mod * fix: generate files * fix(eventstore): tests * fix(eventstore): rename modifier to editor * fix(migrations): add cluster migration, fix(migrations): fix typo of host in clean clsuter * fix(eventstore): move health * fix(eventstore): AggregateTypeFilter aggregateType as param * code quality * fix: go tests * feat: add member funcs * feat: add member model * feat: add member events * feat: add member repo model * fix: better error func testing * fix: project member funcs * fix: add tests * fix: add tests * feat: implement member requests * fix: merge master * fix: merge master * fix: read existing in project repo * fix: fix tests * feat: add internal cache * feat: add cache mock * fix: return values of cache mock * feat: add project role * fix: add cache config * fix: add role to eventstore * fix: use eventstore sdk * fix: use eventstore sdk * fix: add project role grpc requests * fix: fix getby id * fix: changes for mr * fix: change value to interface * feat: add app event creations * fix: searchmethods * Update internal/project/model/project_member.go Co-Authored-By: Silvan <silvan.reusser@gmail.com> * fix: use get project func * fix: append events * fix: check if value is string on equal ignore case * fix: add changes test * fix: add go mod * fix: add some tests * fix: return err not nil * fix: return err not nil * fix: add aggregate funcs and tests * fix: add oidc aggregate funcs and tests * fix: add oidc * fix: add some tests * fix: tests * feat: eventstore repository * fix: remove gorm * version * feat: pkg * feat: eventstore without eventstore-lib * rename files * gnueg * fix: global model * feat: add global view functions * feat(eventstore): sdk * fix(eventstore): rename app to eventstore * delete empty test * fix(models): delete unused struct * feat(eventstore): overwrite context data * fix: use global sql config * fix: oidc validation * fix: generate client secret * fix: generate client id * fix: test change app * fix: deactivate/reactivate application * fix: change oidc config * fix: change oidc config secret * begin models * begin repo * fix: implement grpc app funcs * fix: add application requests * fix: converter * fix: converter * fix: converter and generate clientid * fix: tests * feat: project grant aggregate * feat: project grant * fix: project grant check if role existing * fix: project grant requests * fix: project grant fixes * fix: project grant member model * fix: project grant member aggregate * fix: project grant member eventstore * fix: project grant member requests * feat: user model * begin repo * repo models and more * feat: user command side * lots of functions * user command side * profile requests * commit before rebase on user * save * local config with gopass and more * begin new auth command (user centric) * Update internal/user/model/user.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/address.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/address.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/email.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/email.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/email.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/mfa.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/mfa.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/password.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/password.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/password.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/phone.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/phone.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/phone.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/user.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/user.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/user.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/usergrant/repository/eventsourcing/model/user_grant.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/usergrant/repository/eventsourcing/model/user_grant.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/usergrant/repository/eventsourcing/user_grant.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/user_test.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/eventstore_mock_test.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * changes from mr review * save files into basedir * changes from mr review * changes from mr review * move to auth request * Update internal/usergrant/repository/eventsourcing/cache.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/usergrant/repository/eventsourcing/cache.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * changes requested on mr * fix generate codes * fix return if no events * password code * email verification step * more steps * lot of mfa * begin tests * more next steps * auth api * auth api (user) * auth api (user) * auth api (user) * differ requests * merge * tests * fix compilation error * mock for id generator * Update internal/user/repository/eventsourcing/model/password.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/user/repository/eventsourcing/model/user.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * requests of mr * check email * begin separation of command and query * otp * change packages * some cleanup and fixes * tests for auth request / next steps * add VerificationLifetimes to config and make it run * tests * fix code challenge validation * cleanup * fix merge * begin view * repackaging tests and configs * fix startup config for auth * add migration * add PromptSelectAccount * fix copy / paste * remove user_agent files * fixes * fix sequences in user_session * token commands * token queries and signout * fix * fix set password test * add token handler and table * handle session init * add session state * add user view test cases * change VerifyMyMfaOTP * some fixes * fix user repo in auth api * cleanup * add user session view test * fix merge * fixes * Update internal/auth/repository/eventsourcing/eventstore/auth_request.go Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> * Update internal/auth/repository/eventsourcing/eventstore/auth_request.go Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> * Update internal/auth/repository/eventsourcing/eventstore/auth_request.go Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> * Update internal/auth/repository/eventsourcing/eventstore/auth_request.go Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> * extract method usersForUserSelection * add todo for policy check * id on auth req * fix enum name Co-authored-by: Fabiennne <fabienne.gerschwiler@gmail.com> Co-authored-by: adlerhurst <silvan.reusser@gmail.com> Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
This commit is contained in:
82
internal/auth_request/model/auth_request.go
Normal file
82
internal/auth_request/model/auth_request.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type AuthRequest struct {
|
||||
ID string
|
||||
AgentID string
|
||||
CreationDate time.Time
|
||||
ChangeDate time.Time
|
||||
BrowserInfo *BrowserInfo
|
||||
ApplicationID string
|
||||
CallbackURI string
|
||||
TransferState string
|
||||
Prompt Prompt
|
||||
PossibleLOAs []LevelOfAssurance
|
||||
UiLocales []string
|
||||
LoginHint string
|
||||
PreselectedUserID string
|
||||
MaxAuthAge uint32
|
||||
Request Request
|
||||
|
||||
levelOfAssurance LevelOfAssurance
|
||||
projectApplicationIDs []string
|
||||
UserID string
|
||||
PossibleSteps []NextStep
|
||||
}
|
||||
|
||||
type Prompt int32
|
||||
|
||||
const (
|
||||
PromptUnspecified Prompt = iota
|
||||
PromptNone
|
||||
PromptLogin
|
||||
PromptConsent
|
||||
PromptSelectAccount
|
||||
)
|
||||
|
||||
type LevelOfAssurance int
|
||||
|
||||
const (
|
||||
LevelOfAssuranceNone LevelOfAssurance = iota
|
||||
)
|
||||
|
||||
func NewAuthRequest(id, agentID string, info *BrowserInfo, applicationID, callbackURI, transferState string,
|
||||
prompt Prompt, possibleLOAs []LevelOfAssurance, uiLocales []string, loginHint, preselectedUserID string, maxAuthAge uint32, request Request) *AuthRequest {
|
||||
return &AuthRequest{
|
||||
ID: id,
|
||||
AgentID: agentID,
|
||||
BrowserInfo: info,
|
||||
ApplicationID: applicationID,
|
||||
CallbackURI: callbackURI,
|
||||
TransferState: transferState,
|
||||
Prompt: prompt,
|
||||
PossibleLOAs: possibleLOAs,
|
||||
UiLocales: uiLocales,
|
||||
LoginHint: loginHint,
|
||||
PreselectedUserID: preselectedUserID,
|
||||
MaxAuthAge: maxAuthAge,
|
||||
Request: request,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AuthRequest) IsValid() bool {
|
||||
return a.ID != "" &&
|
||||
a.AgentID != "" &&
|
||||
a.BrowserInfo != nil && a.BrowserInfo.IsValid() &&
|
||||
a.ApplicationID != "" &&
|
||||
a.CallbackURI != "" &&
|
||||
a.Request != nil && a.Request.IsValid()
|
||||
}
|
||||
|
||||
func (a *AuthRequest) MfaLevel() MfaLevel {
|
||||
return -1
|
||||
//PLANNED: check a.PossibleLOAs (and Prompt Login?)
|
||||
}
|
||||
|
||||
func (a *AuthRequest) WithCurrentInfo(info *BrowserInfo) *AuthRequest {
|
||||
a.BrowserInfo = info
|
||||
return a
|
||||
}
|
263
internal/auth_request/model/auth_request_test.go
Normal file
263
internal/auth_request/model/auth_request_test.go
Normal file
@@ -0,0 +1,263 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"net"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAuthRequest_IsValid(t *testing.T) {
|
||||
type fields struct {
|
||||
ID string
|
||||
AgentID string
|
||||
BrowserInfo *BrowserInfo
|
||||
ApplicationID string
|
||||
CallbackURI string
|
||||
Request Request
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
"missing id, false",
|
||||
fields{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"missing agent id, false",
|
||||
fields{
|
||||
ID: "id",
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"missing browser info, false",
|
||||
fields{
|
||||
ID: "id",
|
||||
AgentID: "agentID",
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"browser info invalid, false",
|
||||
fields{
|
||||
ID: "id",
|
||||
AgentID: "agentID",
|
||||
BrowserInfo: &BrowserInfo{},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"missing application id, false",
|
||||
fields{
|
||||
ID: "id",
|
||||
AgentID: "agentID",
|
||||
BrowserInfo: &BrowserInfo{
|
||||
UserAgent: "user agent",
|
||||
AcceptLanguage: "accept language",
|
||||
RemoteIP: net.IPv4(29, 4, 20, 19),
|
||||
},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"missing callback uri, false",
|
||||
fields{
|
||||
ID: "id",
|
||||
AgentID: "agentID",
|
||||
BrowserInfo: &BrowserInfo{
|
||||
UserAgent: "user agent",
|
||||
AcceptLanguage: "accept language",
|
||||
RemoteIP: net.IPv4(29, 4, 20, 19),
|
||||
},
|
||||
ApplicationID: "appID",
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"missing request, false",
|
||||
fields{
|
||||
ID: "id",
|
||||
AgentID: "agentID",
|
||||
BrowserInfo: &BrowserInfo{
|
||||
UserAgent: "user agent",
|
||||
AcceptLanguage: "accept language",
|
||||
RemoteIP: net.IPv4(29, 4, 20, 19),
|
||||
},
|
||||
ApplicationID: "appID",
|
||||
CallbackURI: "schema://callback",
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"request invalid, false",
|
||||
fields{
|
||||
ID: "id",
|
||||
AgentID: "agentID",
|
||||
BrowserInfo: &BrowserInfo{
|
||||
UserAgent: "user agent",
|
||||
AcceptLanguage: "accept language",
|
||||
RemoteIP: net.IPv4(29, 4, 20, 19),
|
||||
},
|
||||
ApplicationID: "appID",
|
||||
CallbackURI: "schema://callback",
|
||||
Request: &AuthRequestOIDC{},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid auth request, true",
|
||||
fields{
|
||||
ID: "id",
|
||||
AgentID: "agentID",
|
||||
BrowserInfo: &BrowserInfo{
|
||||
UserAgent: "user agent",
|
||||
AcceptLanguage: "accept language",
|
||||
RemoteIP: net.IPv4(29, 4, 20, 19),
|
||||
},
|
||||
ApplicationID: "appID",
|
||||
CallbackURI: "schema://callback",
|
||||
Request: &AuthRequestOIDC{
|
||||
Scopes: []string{"openid"},
|
||||
CodeChallenge: &OIDCCodeChallenge{
|
||||
Challenge: "challenge",
|
||||
Method: CodeChallengeMethodS256,
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
a := &AuthRequest{
|
||||
ID: tt.fields.ID,
|
||||
AgentID: tt.fields.AgentID,
|
||||
BrowserInfo: tt.fields.BrowserInfo,
|
||||
ApplicationID: tt.fields.ApplicationID,
|
||||
CallbackURI: tt.fields.CallbackURI,
|
||||
Request: tt.fields.Request,
|
||||
}
|
||||
if got := a.IsValid(); got != tt.want {
|
||||
t.Errorf("IsValid() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthRequest_MfaLevel(t *testing.T) {
|
||||
type fields struct {
|
||||
Prompt Prompt
|
||||
PossibleLOAs []LevelOfAssurance
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want MfaLevel
|
||||
}{
|
||||
//PLANNED: Add / replace test cases when LOA is set
|
||||
{"-1",
|
||||
fields{},
|
||||
-1,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
a := &AuthRequest{
|
||||
Prompt: tt.fields.Prompt,
|
||||
PossibleLOAs: tt.fields.PossibleLOAs,
|
||||
}
|
||||
if got := a.MfaLevel(); got != tt.want {
|
||||
t.Errorf("MfaLevel() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthRequest_WithCurrentInfo(t *testing.T) {
|
||||
type fields struct {
|
||||
ID string
|
||||
AgentID string
|
||||
BrowserInfo *BrowserInfo
|
||||
}
|
||||
type args struct {
|
||||
info *BrowserInfo
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want *AuthRequest
|
||||
}{
|
||||
{
|
||||
"unchanged",
|
||||
fields{
|
||||
ID: "id",
|
||||
AgentID: "agentID",
|
||||
BrowserInfo: &BrowserInfo{
|
||||
UserAgent: "ua",
|
||||
AcceptLanguage: "de",
|
||||
RemoteIP: net.IPv4(29, 4, 20, 19),
|
||||
},
|
||||
},
|
||||
args{
|
||||
&BrowserInfo{
|
||||
UserAgent: "ua",
|
||||
AcceptLanguage: "de",
|
||||
RemoteIP: net.IPv4(29, 4, 20, 19),
|
||||
},
|
||||
},
|
||||
&AuthRequest{
|
||||
ID: "id",
|
||||
AgentID: "agentID",
|
||||
BrowserInfo: &BrowserInfo{
|
||||
UserAgent: "ua",
|
||||
AcceptLanguage: "de",
|
||||
RemoteIP: net.IPv4(29, 4, 20, 19),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"changed",
|
||||
fields{
|
||||
ID: "id",
|
||||
AgentID: "agentID",
|
||||
BrowserInfo: &BrowserInfo{
|
||||
UserAgent: "ua",
|
||||
AcceptLanguage: "de",
|
||||
RemoteIP: net.IPv4(29, 4, 20, 19),
|
||||
},
|
||||
},
|
||||
args{
|
||||
&BrowserInfo{
|
||||
UserAgent: "ua",
|
||||
AcceptLanguage: "de",
|
||||
RemoteIP: net.IPv4(16, 12, 20, 19),
|
||||
},
|
||||
},
|
||||
&AuthRequest{
|
||||
ID: "id",
|
||||
AgentID: "agentID",
|
||||
BrowserInfo: &BrowserInfo{
|
||||
UserAgent: "ua",
|
||||
AcceptLanguage: "de",
|
||||
RemoteIP: net.IPv4(16, 12, 20, 19),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
a := &AuthRequest{
|
||||
ID: tt.fields.ID,
|
||||
AgentID: tt.fields.AgentID,
|
||||
BrowserInfo: tt.fields.BrowserInfo,
|
||||
}
|
||||
if got := a.WithCurrentInfo(tt.args.info); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("WithCurrentInfo() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
15
internal/auth_request/model/browser_info.go
Normal file
15
internal/auth_request/model/browser_info.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package model
|
||||
|
||||
import "net"
|
||||
|
||||
type BrowserInfo struct {
|
||||
UserAgent string
|
||||
AcceptLanguage string
|
||||
RemoteIP net.IP
|
||||
}
|
||||
|
||||
func (i *BrowserInfo) IsValid() bool {
|
||||
return i.UserAgent != "" &&
|
||||
i.AcceptLanguage != "" &&
|
||||
i.RemoteIP != nil && !i.RemoteIP.IsUnspecified()
|
||||
}
|
17
internal/auth_request/model/code_challenge.go
Normal file
17
internal/auth_request/model/code_challenge.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package model
|
||||
|
||||
type OIDCCodeChallenge struct {
|
||||
Challenge string
|
||||
Method OIDCCodeChallengeMethod
|
||||
}
|
||||
|
||||
func (c *OIDCCodeChallenge) IsValid() bool {
|
||||
return c.Challenge != ""
|
||||
}
|
||||
|
||||
type OIDCCodeChallengeMethod int32
|
||||
|
||||
const (
|
||||
CodeChallengeMethodPlain OIDCCodeChallengeMethod = iota
|
||||
CodeChallengeMethodS256
|
||||
)
|
117
internal/auth_request/model/next_step.go
Normal file
117
internal/auth_request/model/next_step.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package model
|
||||
|
||||
type NextStep interface {
|
||||
Type() NextStepType
|
||||
}
|
||||
|
||||
type NextStepType int32
|
||||
|
||||
const (
|
||||
NextStepUnspecified NextStepType = iota
|
||||
NextStepLogin
|
||||
NextStepUserSelection
|
||||
NextStepPassword
|
||||
NextStepChangePassword
|
||||
NextStepInitPassword
|
||||
NextStepVerifyEmail
|
||||
NextStepMfaPrompt
|
||||
NextStepMfaVerify
|
||||
NextStepRedirectToCallback
|
||||
)
|
||||
|
||||
type UserSessionState int32
|
||||
|
||||
const (
|
||||
UserSessionStateActive UserSessionState = iota
|
||||
UserSessionStateTerminated
|
||||
)
|
||||
|
||||
type LoginStep struct {
|
||||
NotFound bool
|
||||
}
|
||||
|
||||
func (s *LoginStep) Type() NextStepType {
|
||||
return NextStepLogin
|
||||
}
|
||||
|
||||
type SelectUserStep struct {
|
||||
Users []UserSelection
|
||||
}
|
||||
|
||||
func (s *SelectUserStep) Type() NextStepType {
|
||||
return NextStepUserSelection
|
||||
}
|
||||
|
||||
type UserSelection struct {
|
||||
UserID string
|
||||
UserName string
|
||||
UserSessionState UserSessionState
|
||||
}
|
||||
|
||||
type PasswordStep struct {
|
||||
FailureCount uint16
|
||||
}
|
||||
|
||||
func (s *PasswordStep) Type() NextStepType {
|
||||
return NextStepPassword
|
||||
}
|
||||
|
||||
type ChangePasswordStep struct {
|
||||
}
|
||||
|
||||
func (s *ChangePasswordStep) Type() NextStepType {
|
||||
return NextStepChangePassword
|
||||
}
|
||||
|
||||
type InitPasswordStep struct {
|
||||
}
|
||||
|
||||
func (s *InitPasswordStep) Type() NextStepType {
|
||||
return NextStepInitPassword
|
||||
}
|
||||
|
||||
type VerifyEMailStep struct {
|
||||
}
|
||||
|
||||
func (s *VerifyEMailStep) Type() NextStepType {
|
||||
return NextStepVerifyEmail
|
||||
}
|
||||
|
||||
type MfaPromptStep struct {
|
||||
Required bool
|
||||
MfaProviders []MfaType
|
||||
}
|
||||
|
||||
func (s *MfaPromptStep) Type() NextStepType {
|
||||
return NextStepMfaPrompt
|
||||
}
|
||||
|
||||
type MfaVerificationStep struct {
|
||||
FailureCount uint16
|
||||
MfaProviders []MfaType
|
||||
}
|
||||
|
||||
func (s *MfaVerificationStep) Type() NextStepType {
|
||||
return NextStepMfaVerify
|
||||
}
|
||||
|
||||
type RedirectToCallbackStep struct {
|
||||
}
|
||||
|
||||
func (s *RedirectToCallbackStep) Type() NextStepType {
|
||||
return NextStepRedirectToCallback
|
||||
}
|
||||
|
||||
type MfaType int
|
||||
|
||||
const (
|
||||
MfaTypeOTP MfaType = iota
|
||||
)
|
||||
|
||||
type MfaLevel int
|
||||
|
||||
const (
|
||||
MfaLevelSoftware MfaLevel = iota
|
||||
MfaLevelHardware
|
||||
MfaLevelHardwareCertified
|
||||
)
|
48
internal/auth_request/model/request.go
Normal file
48
internal/auth_request/model/request.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package model
|
||||
|
||||
type Request interface {
|
||||
Type() AuthRequestType
|
||||
IsValid() bool
|
||||
}
|
||||
|
||||
type AuthRequestType int32
|
||||
|
||||
const (
|
||||
AuthRequestTypeOIDC AuthRequestType = iota
|
||||
AuthRequestTypeSAML
|
||||
)
|
||||
|
||||
type AuthRequestOIDC struct {
|
||||
Scopes []string
|
||||
ResponseType OIDCResponseType
|
||||
Nonce string
|
||||
CodeChallenge *OIDCCodeChallenge
|
||||
}
|
||||
|
||||
func (a *AuthRequestOIDC) Type() AuthRequestType {
|
||||
return AuthRequestTypeOIDC
|
||||
}
|
||||
|
||||
func (a *AuthRequestOIDC) IsValid() bool {
|
||||
return len(a.Scopes) > 0 &&
|
||||
a.CodeChallenge == nil || a.CodeChallenge != nil && a.CodeChallenge.IsValid()
|
||||
}
|
||||
|
||||
type AuthRequestSAML struct {
|
||||
}
|
||||
|
||||
func (a *AuthRequestSAML) Type() AuthRequestType {
|
||||
return AuthRequestTypeSAML
|
||||
}
|
||||
|
||||
func (a *AuthRequestSAML) IsValid() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type OIDCResponseType int32
|
||||
|
||||
const (
|
||||
OIDCResponseTypeCode OIDCResponseType = iota
|
||||
OIDCResponseTypeIdToken
|
||||
OIDCResponseTypeToken
|
||||
)
|
67
internal/auth_request/repository/cache/cache.go
vendored
Normal file
67
internal/auth_request/repository/cache/cache.go
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/caos/zitadel/internal/auth_request/model"
|
||||
"github.com/caos/zitadel/internal/config/types"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Connection types.SQL
|
||||
}
|
||||
|
||||
type AuthRequestCache struct {
|
||||
client *sql.DB
|
||||
}
|
||||
|
||||
func Start(conf Config) (*AuthRequestCache, error) {
|
||||
client, err := sql.Open("postgres", conf.Connection.ConnectionString())
|
||||
if err != nil {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(err, "SQL-9qBtr", "unable to open database connection")
|
||||
}
|
||||
return &AuthRequestCache{
|
||||
client: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *AuthRequestCache) Health(ctx context.Context) error {
|
||||
return c.client.PingContext(ctx)
|
||||
}
|
||||
|
||||
func (c *AuthRequestCache) GetAuthRequestByID(_ context.Context, id string) (*model.AuthRequest, error) {
|
||||
var b []byte
|
||||
err := c.client.QueryRow("SELECT request FROM auth.authrequests WHERE id = ?", id).Scan(&b)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, caos_errs.ThrowNotFound(err, "CACHE-d24aD", "auth request not found")
|
||||
}
|
||||
return nil, caos_errs.ThrowInternal(err, "CACHE-as3kj", "unable to get auth request from database")
|
||||
}
|
||||
request := new(model.AuthRequest)
|
||||
err = json.Unmarshal(b, &request)
|
||||
if err != nil {
|
||||
return nil, caos_errs.ThrowInternal(err, "CACHE-2wshg", "unable to unmarshal auth request")
|
||||
}
|
||||
return request, nil
|
||||
}
|
||||
|
||||
func (c *AuthRequestCache) SaveAuthRequest(_ context.Context, request *model.AuthRequest) error {
|
||||
b, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return caos_errs.ThrowInternal(err, "CACHE-32FH9", "unable to marshal auth request")
|
||||
}
|
||||
stmt, err := c.client.Prepare("INSERT INTO auth.authrequests (id, request) VALUES($1, $2)")
|
||||
if err != nil {
|
||||
return caos_errs.ThrowInternal(err, "CACHE-dswfF", "sql prepare failed")
|
||||
}
|
||||
_, err = stmt.Exec(request.ID, b)
|
||||
if err != nil {
|
||||
return caos_errs.ThrowInternal(err, "CACHE-sw4af", "unable to save auth request")
|
||||
}
|
||||
return nil
|
||||
}
|
3
internal/auth_request/repository/gen_mock.go
Normal file
3
internal/auth_request/repository/gen_mock.go
Normal file
@@ -0,0 +1,3 @@
|
||||
package repository
|
||||
|
||||
//go:generate mockgen -package mock -destination ./mock/repository.mock.go github.com/caos/zitadel/internal/auth_request/repository Repository
|
12
internal/auth_request/repository/mock/repository.go
Normal file
12
internal/auth_request/repository/mock/repository.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package mock
|
||||
|
||||
import (
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
"github.com/caos/zitadel/internal/auth_request/repository"
|
||||
)
|
||||
|
||||
func NewMockAuthRequestRepository(ctrl *gomock.Controller) repository.Repository {
|
||||
repo := NewMockRepository(ctrl)
|
||||
return repo
|
||||
}
|
79
internal/auth_request/repository/mock/repository.mock.go
Normal file
79
internal/auth_request/repository/mock/repository.mock.go
Normal file
@@ -0,0 +1,79 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/caos/zitadel/internal/auth_request/repository (interfaces: Repository)
|
||||
|
||||
// Package mock is a generated GoMock package.
|
||||
package mock
|
||||
|
||||
import (
|
||||
context "context"
|
||||
model "github.com/caos/zitadel/internal/auth_request/model"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
// MockRepository is a mock of Repository interface
|
||||
type MockRepository struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockRepositoryMockRecorder
|
||||
}
|
||||
|
||||
// MockRepositoryMockRecorder is the mock recorder for MockRepository
|
||||
type MockRepositoryMockRecorder struct {
|
||||
mock *MockRepository
|
||||
}
|
||||
|
||||
// NewMockRepository creates a new mock instance
|
||||
func NewMockRepository(ctrl *gomock.Controller) *MockRepository {
|
||||
mock := &MockRepository{ctrl: ctrl}
|
||||
mock.recorder = &MockRepositoryMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// GetAuthRequestByID mocks base method
|
||||
func (m *MockRepository) GetAuthRequestByID(arg0 context.Context, arg1 string) (*model.AuthRequest, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetAuthRequestByID", arg0, arg1)
|
||||
ret0, _ := ret[0].(*model.AuthRequest)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetAuthRequestByID indicates an expected call of GetAuthRequestByID
|
||||
func (mr *MockRepositoryMockRecorder) GetAuthRequestByID(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthRequestByID", reflect.TypeOf((*MockRepository)(nil).GetAuthRequestByID), arg0, arg1)
|
||||
}
|
||||
|
||||
// Health mocks base method
|
||||
func (m *MockRepository) Health(arg0 context.Context) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Health", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Health indicates an expected call of Health
|
||||
func (mr *MockRepositoryMockRecorder) Health(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Health", reflect.TypeOf((*MockRepository)(nil).Health), arg0)
|
||||
}
|
||||
|
||||
// SaveAuthRequest mocks base method
|
||||
func (m *MockRepository) SaveAuthRequest(arg0 context.Context, arg1 string) (*model.AuthRequest, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SaveAuthRequest", arg0, arg1)
|
||||
ret0, _ := ret[0].(*model.AuthRequest)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// SaveAuthRequest indicates an expected call of SaveAuthRequest
|
||||
func (mr *MockRepositoryMockRecorder) SaveAuthRequest(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveAuthRequest", reflect.TypeOf((*MockRepository)(nil).SaveAuthRequest), arg0, arg1)
|
||||
}
|
14
internal/auth_request/repository/repository.go
Normal file
14
internal/auth_request/repository/repository.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/zitadel/internal/auth_request/model"
|
||||
)
|
||||
|
||||
type Repository interface {
|
||||
Health(ctx context.Context) error
|
||||
|
||||
GetAuthRequestByID(ctx context.Context, id string) (*model.AuthRequest, error)
|
||||
SaveAuthRequest(ctx context.Context, id string) (*model.AuthRequest, error)
|
||||
}
|
Reference in New Issue
Block a user