mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-20 14:34:25 +00:00
Merge commit from fork
* fix: add `Scopes` to `Request` interface so that scopes can be validated on all requests * feat: assert org from scope exists when authorizing requests * fix: check all scopes * comments * check org on callback creation * fix tests * clarifications * fix scope marshaling * fix: enfore organization for authrequest in initiation * fix: filter sessions on the accounts page by organization scope * add integration tests --------- Co-authored-by: Livio Spring <[email protected]> Co-authored-by: Max Peintner <[email protected]>
This commit is contained in:
co-authored by
Livio Spring
Max Peintner
parent
aa4432dc99
commit
c3a6bdb0bb
@@ -17,12 +17,27 @@ export async function generateMetadata(): Promise<Metadata> {
|
||||
return { title: t("title") };
|
||||
}
|
||||
|
||||
async function loadSessions({ serviceConfig }: { serviceConfig: ServiceConfig }) {
|
||||
async function loadSessions({
|
||||
serviceConfig,
|
||||
organization,
|
||||
}: {
|
||||
serviceConfig: ServiceConfig;
|
||||
organization?: string;
|
||||
}) {
|
||||
const cookieIds = await getAllSessionCookieIds();
|
||||
|
||||
if (cookieIds && cookieIds.length) {
|
||||
const response = await listSessions({ serviceConfig, ids: cookieIds.filter((id) => !!id) as string[] });
|
||||
return response?.sessions ?? [];
|
||||
const response = await listSessions({
|
||||
serviceConfig,
|
||||
ids: cookieIds.filter((id) => !!id) as string[],
|
||||
});
|
||||
|
||||
let sessions = response?.sessions ?? [];
|
||||
if (organization) {
|
||||
sessions = sessions.filter((s) => s.factors?.user?.organizationId === organization);
|
||||
}
|
||||
|
||||
return sessions;
|
||||
} else {
|
||||
console.info("No session cookie found.");
|
||||
return [];
|
||||
@@ -46,7 +61,7 @@ export default async function Page(props: { searchParams: Promise<Record<string
|
||||
}
|
||||
}
|
||||
|
||||
let sessions = await loadSessions({ serviceConfig });
|
||||
let sessions = await loadSessions({ serviceConfig, organization });
|
||||
|
||||
const branding = await getBrandingSettings({ serviceConfig, organization: organization ?? defaultOrganization });
|
||||
|
||||
|
||||
@@ -268,7 +268,7 @@ export async function handleOIDCFlowInitiation(params: FlowInitiationParams): Pr
|
||||
} else if (authRequest.prompt.includes(Prompt.NONE)) {
|
||||
const securitySettings = await getSecuritySettings({ serviceConfig });
|
||||
|
||||
const selectedSession = await findValidSession({ serviceConfig, sessions, authRequest });
|
||||
const selectedSession = await findValidSession({ serviceConfig, sessions, authRequest, organization });
|
||||
|
||||
const noSessionResponse = NextResponse.json({ error: "No active session found" }, { status: 400 });
|
||||
setCSPHeaders(noSessionResponse, serviceConfig, securitySettings);
|
||||
@@ -304,7 +304,7 @@ export async function handleOIDCFlowInitiation(params: FlowInitiationParams): Pr
|
||||
|
||||
return callbackResponse;
|
||||
} else {
|
||||
let selectedSession = await findValidSession({ serviceConfig, sessions, authRequest });
|
||||
let selectedSession = await findValidSession({ serviceConfig, sessions, authRequest, organization });
|
||||
|
||||
if (!selectedSession || !selectedSession.id) {
|
||||
return gotoAccounts({
|
||||
|
||||
@@ -142,13 +142,15 @@ export async function findValidSession({
|
||||
sessions,
|
||||
authRequest,
|
||||
samlRequest,
|
||||
organization,
|
||||
}: {
|
||||
serviceConfig: ServiceConfig;
|
||||
sessions: Session[];
|
||||
authRequest?: AuthRequest;
|
||||
samlRequest?: SAMLRequest;
|
||||
organization?: string;
|
||||
}): Promise<Session | undefined> {
|
||||
const sessionsWithHint = sessions.filter((s) => {
|
||||
let sessionsWithHint = sessions.filter((s) => {
|
||||
if (authRequest && authRequest.hintUserId) {
|
||||
return s.factors?.user?.id === authRequest.hintUserId;
|
||||
}
|
||||
@@ -163,6 +165,10 @@ export async function findValidSession({
|
||||
return true;
|
||||
});
|
||||
|
||||
if (organization) {
|
||||
sessionsWithHint = sessionsWithHint.filter((s) => s.factors?.user?.organizationId === organization);
|
||||
}
|
||||
|
||||
if (sessionsWithHint.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/zitadel/oidc/v3/pkg/oidc"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/app"
|
||||
filter "github.com/zitadel/zitadel/pkg/grpc/filter/v2beta"
|
||||
@@ -163,6 +164,25 @@ func TestServer_CreateCallback(t *testing.T) {
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid organization",
|
||||
ctx: CTXLoginClient,
|
||||
req: &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: func() string {
|
||||
org := Instance.CreateOrganization(IAMCTX, integration.OrganizationName(), integration.Email())
|
||||
_, authRequestID, err := Instance.CreateOIDCAuthRequest(CTXLoginClient, client.GetClientId(), Instance.Users.Get(integration.UserTypeLogin).ID, redirectURI, oidc.ScopeOpenID, domain.OrgIDScope+org.OrganizationId)
|
||||
require.NoError(t, err)
|
||||
return authRequestID
|
||||
}(),
|
||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||
Session: &oidc_pb.Session{
|
||||
SessionId: sessionResp.GetSessionId(),
|
||||
SessionToken: sessionResp.GetSessionToken(),
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "fail callback",
|
||||
ctx: CTXLoginClient,
|
||||
@@ -356,6 +376,31 @@ func TestServer_CreateCallback(t *testing.T) {
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "callback with required organization",
|
||||
ctx: CTXLoginClient,
|
||||
req: &oidc_pb.CreateCallbackRequest{
|
||||
AuthRequestId: func() string {
|
||||
_, authRequestID, err := Instance.CreateOIDCAuthRequest(CTXLoginClient, client.GetClientId(), Instance.Users.Get(integration.UserTypeLogin).ID, redirectURI, oidc.ScopeOpenID, domain.OrgIDScope+Instance.DefaultOrg.Id)
|
||||
require.NoError(t, err)
|
||||
return authRequestID
|
||||
}(),
|
||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||
Session: &oidc_pb.Session{
|
||||
SessionId: sessionResp.GetSessionId(),
|
||||
SessionToken: sessionResp.GetSessionToken(),
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &oidc_pb.CreateCallbackResponse{
|
||||
CallbackUrl: `oidcintegrationtest:\/\/callback\?code=(.*)&state=state`,
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
ResourceOwner: Instance.ID(),
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
@@ -749,7 +794,7 @@ func TestServer_AuthorizeOrDenyDeviceAuthorization(t *testing.T) {
|
||||
ctx: CTXLoginClient,
|
||||
req: &oidc_pb.AuthorizeOrDenyDeviceAuthorizationRequest{
|
||||
DeviceAuthorizationId: func() string {
|
||||
req, err := Instance.CreateDeviceAuthorizationRequest(CTXLoginClient, client.GetClientId(), "openid")
|
||||
req, err := Instance.CreateDeviceAuthorizationRequest(CTXLoginClient, client.GetClientId(), oidc.ScopeOpenID)
|
||||
require.NoError(t, err)
|
||||
var id string
|
||||
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTXLoginClient, time.Minute)
|
||||
@@ -776,7 +821,7 @@ func TestServer_AuthorizeOrDenyDeviceAuthorization(t *testing.T) {
|
||||
ctx: CTXLoginClient,
|
||||
req: &oidc_pb.AuthorizeOrDenyDeviceAuthorizationRequest{
|
||||
DeviceAuthorizationId: func() string {
|
||||
req, err := Instance.CreateDeviceAuthorizationRequest(CTXLoginClient, client.GetClientId(), "openid")
|
||||
req, err := Instance.CreateDeviceAuthorizationRequest(CTXLoginClient, client.GetClientId(), oidc.ScopeOpenID)
|
||||
require.NoError(t, err)
|
||||
var id string
|
||||
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTXLoginClient, time.Minute)
|
||||
@@ -798,12 +843,40 @@ func TestServer_AuthorizeOrDenyDeviceAuthorization(t *testing.T) {
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid organization",
|
||||
ctx: CTXLoginClient,
|
||||
req: &oidc_pb.AuthorizeOrDenyDeviceAuthorizationRequest{
|
||||
DeviceAuthorizationId: func() string {
|
||||
org := Instance.CreateOrganization(IAMCTX, integration.OrganizationName(), integration.Email())
|
||||
req, err := Instance.CreateDeviceAuthorizationRequest(CTXLoginClient, client.GetClientId(), oidc.ScopeOpenID, domain.OrgIDScope+org.OrganizationId)
|
||||
require.NoError(t, err)
|
||||
var id string
|
||||
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTXLoginClient, time.Minute)
|
||||
require.EventuallyWithT(t, func(collectT *assert.CollectT) {
|
||||
resp, err := Instance.Client.OIDCv2.GetDeviceAuthorizationRequest(CTXLoginClient, &oidc_pb.GetDeviceAuthorizationRequestRequest{
|
||||
UserCode: req.UserCode,
|
||||
})
|
||||
assert.NoError(collectT, err)
|
||||
id = resp.GetDeviceAuthorizationRequest().GetId()
|
||||
}, retryDuration, tick)
|
||||
return id
|
||||
}(),
|
||||
Decision: &oidc_pb.AuthorizeOrDenyDeviceAuthorizationRequest_Session{
|
||||
Session: &oidc_pb.Session{
|
||||
SessionId: sessionResp.GetSessionId(),
|
||||
SessionToken: sessionResp.GetSessionToken(),
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "deny device authorization",
|
||||
ctx: CTXLoginClient,
|
||||
req: &oidc_pb.AuthorizeOrDenyDeviceAuthorizationRequest{
|
||||
DeviceAuthorizationId: func() string {
|
||||
req, err := Instance.CreateDeviceAuthorizationRequest(CTXLoginClient, client.GetClientId(), "openid")
|
||||
req, err := Instance.CreateDeviceAuthorizationRequest(CTXLoginClient, client.GetClientId(), oidc.ScopeOpenID)
|
||||
require.NoError(t, err)
|
||||
var id string
|
||||
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTXLoginClient, time.Minute)
|
||||
@@ -826,7 +899,7 @@ func TestServer_AuthorizeOrDenyDeviceAuthorization(t *testing.T) {
|
||||
ctx: CTX,
|
||||
req: &oidc_pb.AuthorizeOrDenyDeviceAuthorizationRequest{
|
||||
DeviceAuthorizationId: func() string {
|
||||
req, err := Instance.CreateDeviceAuthorizationRequest(CTXLoginClient, client.GetClientId(), "openid")
|
||||
req, err := Instance.CreateDeviceAuthorizationRequest(CTXLoginClient, client.GetClientId(), oidc.ScopeOpenID)
|
||||
require.NoError(t, err)
|
||||
var id string
|
||||
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTXLoginClient, time.Minute)
|
||||
@@ -849,7 +922,7 @@ func TestServer_AuthorizeOrDenyDeviceAuthorization(t *testing.T) {
|
||||
ctx: CTX,
|
||||
req: &oidc_pb.AuthorizeOrDenyDeviceAuthorizationRequest{
|
||||
DeviceAuthorizationId: func() string {
|
||||
req, err := Instance.CreateDeviceAuthorizationRequest(CTXLoginClient, client.GetClientId(), "openid")
|
||||
req, err := Instance.CreateDeviceAuthorizationRequest(CTXLoginClient, client.GetClientId(), oidc.ScopeOpenID)
|
||||
require.NoError(t, err)
|
||||
var id string
|
||||
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTXLoginClient, time.Minute)
|
||||
@@ -876,7 +949,34 @@ func TestServer_AuthorizeOrDenyDeviceAuthorization(t *testing.T) {
|
||||
ctx: CTXLoginClient,
|
||||
req: &oidc_pb.AuthorizeOrDenyDeviceAuthorizationRequest{
|
||||
DeviceAuthorizationId: func() string {
|
||||
req, err := Instance.CreateDeviceAuthorizationRequest(CTXLoginClient, client.GetClientId(), "openid")
|
||||
req, err := Instance.CreateDeviceAuthorizationRequest(CTXLoginClient, client.GetClientId(), oidc.ScopeOpenID)
|
||||
require.NoError(t, err)
|
||||
var id string
|
||||
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTXLoginClient, time.Minute)
|
||||
require.EventuallyWithT(t, func(collectT *assert.CollectT) {
|
||||
resp, err := Instance.Client.OIDCv2.GetDeviceAuthorizationRequest(CTXLoginClient, &oidc_pb.GetDeviceAuthorizationRequestRequest{
|
||||
UserCode: req.UserCode,
|
||||
})
|
||||
assert.NoError(collectT, err)
|
||||
id = resp.GetDeviceAuthorizationRequest().GetId()
|
||||
}, retryDuration, tick)
|
||||
return id
|
||||
}(),
|
||||
Decision: &oidc_pb.AuthorizeOrDenyDeviceAuthorizationRequest_Session{
|
||||
Session: &oidc_pb.Session{
|
||||
SessionId: sessionResp.GetSessionId(),
|
||||
SessionToken: sessionResp.GetSessionToken(),
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "authorize, with organization scope",
|
||||
ctx: CTXLoginClient,
|
||||
req: &oidc_pb.AuthorizeOrDenyDeviceAuthorizationRequest{
|
||||
DeviceAuthorizationId: func() string {
|
||||
req, err := Instance.CreateDeviceAuthorizationRequest(CTXLoginClient, client.GetClientId(), oidc.ScopeOpenID, domain.OrgIDScope+Instance.DefaultOrg.GetId())
|
||||
require.NoError(t, err)
|
||||
var id string
|
||||
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTXLoginClient, time.Minute)
|
||||
|
||||
@@ -80,25 +80,31 @@ func (o *OPStorage) CreateAuthRequest(ctx context.Context, req *oidc.AuthRequest
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OPStorage) createAuthRequestScopeAndAudience(ctx context.Context, clientID string, reqScope []string) (scope, audience []string, err error) {
|
||||
func (o *OPStorage) createAuthRequestScopeAndAudience(ctx context.Context, clientID string, reqScope []string) (scope, audience []string, orgID string, err error) {
|
||||
project, err := o.query.ProjectByClientID(ctx, clientID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, "", err
|
||||
}
|
||||
|
||||
orgID, err = o.assertOrgScope(ctx, reqScope)
|
||||
if err != nil {
|
||||
return nil, nil, "", err
|
||||
}
|
||||
|
||||
scope, err = o.assertProjectRoleScopesByProject(ctx, project, reqScope)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, "", err
|
||||
}
|
||||
audience, err = o.audienceFromProjectID(ctx, project.ID)
|
||||
audience = domain.AddAudScopeToAudience(ctx, audience, scope)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, "", err
|
||||
}
|
||||
return scope, audience, nil
|
||||
return scope, audience, orgID, nil
|
||||
}
|
||||
|
||||
func (o *OPStorage) createAuthRequestLoginClient(ctx context.Context, req *oidc.AuthRequest, hintUserID, loginClient string) (op.AuthRequest, error) {
|
||||
scope, audience, err := o.createAuthRequestScopeAndAudience(ctx, req.ClientID, req.Scopes)
|
||||
scope, audience, orgID, err := o.createAuthRequestScopeAndAudience(ctx, req.ClientID, req.Scopes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -118,6 +124,7 @@ func (o *OPStorage) createAuthRequestLoginClient(ctx context.Context, req *oidc.
|
||||
UILocales: UILocalesToBusiness(req.UILocales),
|
||||
MaxAge: MaxAgeToBusiness(req.MaxAge),
|
||||
Issuer: o.contextToIssuer(ctx),
|
||||
OrganizationID: orgID,
|
||||
}
|
||||
if req.LoginHint != "" {
|
||||
authRequest.LoginHint = &req.LoginHint
|
||||
@@ -138,7 +145,8 @@ func (o *OPStorage) createAuthRequest(ctx context.Context, req *oidc.AuthRequest
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "OIDC-sd436", "no user agent id")
|
||||
}
|
||||
scope, audience, err := o.createAuthRequestScopeAndAudience(ctx, req.ClientID, req.Scopes)
|
||||
// we do not need to handle the orgID for the v1 login, since it handles it already
|
||||
scope, audience, _, err := o.createAuthRequestScopeAndAudience(ctx, req.ClientID, req.Scopes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -530,6 +538,39 @@ func (o *OPStorage) GetRefreshTokenInfo(ctx context.Context, clientID string, to
|
||||
return refreshToken.UserID, refreshToken.ID, nil
|
||||
}
|
||||
|
||||
// assertOrgScope checks the scopes for organization scopes and returns the orgID if exactly one org scope is found.
|
||||
// If multiple org scopes are found or if the org scope is invalid, an error is returned.
|
||||
// For backwards compatibility, we support both orgID and orgDomain scopes, but they need to be consistent,
|
||||
// meaning that if both are provided, they need to belong to the same organization.
|
||||
func (o *OPStorage) assertOrgScope(ctx context.Context, scopes []string) (string, error) {
|
||||
var id string
|
||||
for _, scope := range scopes {
|
||||
if orgID, ok := strings.CutPrefix(scope, domain.OrgIDScope); ok {
|
||||
org, err := o.query.OrgByID(ctx, orgID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if id != "" && id != org.ID {
|
||||
return "", oidc.ErrInvalidScope().WithDescription("Only one organization scope may be provided")
|
||||
}
|
||||
id = org.ID
|
||||
continue
|
||||
}
|
||||
|
||||
if orgDomain, ok := strings.CutPrefix(scope, domain.OrgDomainPrimaryScope); ok {
|
||||
org, err := o.query.OrgByPrimaryDomain(ctx, orgDomain)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if id != "" && id != org.ID {
|
||||
return "", oidc.ErrInvalidScope().WithDescription("Only one organization scope may be provided")
|
||||
}
|
||||
id = org.ID
|
||||
}
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (o *OPStorage) assertProjectRoleScopesByProject(ctx context.Context, project *query.Project, scopes []string) ([]string, error) {
|
||||
for _, scope := range scopes {
|
||||
if strings.HasPrefix(scope, ScopeProjectRolePrefix) {
|
||||
|
||||
@@ -119,13 +119,13 @@ func CreateAuthRequestToBusiness(ctx context.Context, authReq *oidc.AuthRequest,
|
||||
UserID: userID,
|
||||
InstanceID: authz.GetInstance(ctx).InstanceID(),
|
||||
Audience: audience,
|
||||
Request: &domain.AuthRequestOIDC{
|
||||
Scopes: authReq.Scopes,
|
||||
ResponseType: ResponseTypeToBusiness(authReq.ResponseType),
|
||||
ResponseMode: ResponseModeToBusiness(authReq.ResponseMode),
|
||||
Nonce: authReq.Nonce,
|
||||
CodeChallenge: CodeChallengeToBusiness(authReq.CodeChallenge, authReq.CodeChallengeMethod),
|
||||
},
|
||||
Request: domain.NewAuthRequestOIDC(
|
||||
authReq.Scopes,
|
||||
ResponseTypeToBusiness(authReq.ResponseType),
|
||||
ResponseModeToBusiness(authReq.ResponseMode),
|
||||
authReq.Nonce,
|
||||
CodeChallengeToBusiness(authReq.CodeChallenge, authReq.CodeChallengeMethod),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,11 +76,11 @@ func (o *OPStorage) StoreDeviceAuthorization(ctx context.Context, clientID, devi
|
||||
logger.OnError(err).Error(logMsg)
|
||||
span.EndWithError(err)
|
||||
}()
|
||||
scope, audience, err := o.createAuthRequestScopeAndAudience(ctx, clientID, scope)
|
||||
scope, audience, orgID, err := o.createAuthRequestScopeAndAudience(ctx, clientID, scope)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
details, err := o.command.AddDeviceAuth(ctx, clientID, deviceCode, userCode, expires, scope, audience, slices.Contains(scope, oidc.ScopeOfflineAccess))
|
||||
details, err := o.command.AddDeviceAuth(ctx, clientID, deviceCode, userCode, orgID, expires, scope, audience, slices.Contains(scope, oidc.ScopeOfflineAccess))
|
||||
if err == nil {
|
||||
logger.SetFields("details", details).Debug(logMsg)
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
http_utils "github.com/zitadel/zitadel/internal/api/http"
|
||||
oidc_api "github.com/zitadel/zitadel/internal/api/oidc"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
oidc_pb "github.com/zitadel/zitadel/pkg/grpc/oidc/v2"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/session/v2"
|
||||
@@ -36,6 +37,20 @@ func TestOPStorage_CreateAuthRequest(t *testing.T) {
|
||||
|
||||
id2 := createAuthRequestNoLoginClientHeader(t, Instance, clientIDV2, redirectURI)
|
||||
require.Contains(t, id2, command.IDPrefixV2)
|
||||
|
||||
// valid org scope must succeed
|
||||
_, _, err := Instance.CreateOIDCAuthRequest(CTX, clientID, Instance.Users.Get(integration.UserTypeLogin).ID, redirectURI, oidc.ScopeOpenID, domain.OrgIDScope+Instance.DefaultOrg.Id)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, _, err = Instance.CreateOIDCAuthRequest(CTX, clientID, Instance.Users.Get(integration.UserTypeLogin).ID, redirectURI, oidc.ScopeOpenID, domain.OrgIDScope+Instance.DefaultOrg.Id)
|
||||
require.NoError(t, err)
|
||||
|
||||
// invalid org scope must fail
|
||||
_, _, err = Instance.CreateOIDCAuthRequest(CTX, clientID, Instance.Users.Get(integration.UserTypeLogin).ID, redirectURI, oidc.ScopeOpenID, domain.OrgIDScope+"invalid")
|
||||
require.Error(t, err)
|
||||
|
||||
_, _, err = Instance.CreateOIDCAuthRequest(CTX, clientID, Instance.Users.Get(integration.UserTypeLogin).ID, redirectURI, oidc.ScopeOpenID, domain.OrgIDScope+"invalid")
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestOPStorage_CreateAccessToken_code(t *testing.T) {
|
||||
|
||||
@@ -30,6 +30,7 @@ type AuthRequest struct {
|
||||
HintUserID *string
|
||||
NeedRefreshToken bool
|
||||
Issuer string
|
||||
OrganizationID string
|
||||
}
|
||||
|
||||
type CurrentAuthRequest struct {
|
||||
@@ -75,6 +76,7 @@ func (c *Commands) AddAuthRequest(ctx context.Context, authRequest *AuthRequest)
|
||||
authRequest.HintUserID,
|
||||
authRequest.NeedRefreshToken,
|
||||
authRequest.Issuer,
|
||||
authRequest.OrganizationID,
|
||||
))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -116,6 +118,9 @@ func (c *Commands) LinkSessionToAuthRequest(ctx context.Context, id, sessionID,
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
if writeModel.OrganizationID != "" && writeModel.OrganizationID != sessionWriteModel.UserResourceOwner {
|
||||
return nil, nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-59ljd", "Errors.User.NotAllowedOrg")
|
||||
}
|
||||
|
||||
if err := c.pushAppendAndReduce(ctx, writeModel, authrequest.NewSessionLinkedEvent(
|
||||
ctx, &authrequest.NewAggregate(id, authz.GetInstance(ctx).InstanceID()).Aggregate,
|
||||
@@ -171,23 +176,24 @@ func (c *Commands) AddAuthRequestCode(ctx context.Context, authRequestID, code s
|
||||
func authRequestWriteModelToCurrentAuthRequest(writeModel *AuthRequestWriteModel) (_ *CurrentAuthRequest) {
|
||||
return &CurrentAuthRequest{
|
||||
AuthRequest: &AuthRequest{
|
||||
ID: writeModel.AggregateID,
|
||||
LoginClient: writeModel.LoginClient,
|
||||
ClientID: writeModel.ClientID,
|
||||
RedirectURI: writeModel.RedirectURI,
|
||||
State: writeModel.State,
|
||||
Nonce: writeModel.Nonce,
|
||||
Scope: writeModel.Scope,
|
||||
Audience: writeModel.Audience,
|
||||
ResponseType: writeModel.ResponseType,
|
||||
ResponseMode: writeModel.ResponseMode,
|
||||
CodeChallenge: writeModel.CodeChallenge,
|
||||
Prompt: writeModel.Prompt,
|
||||
UILocales: writeModel.UILocales,
|
||||
MaxAge: writeModel.MaxAge,
|
||||
LoginHint: writeModel.LoginHint,
|
||||
HintUserID: writeModel.HintUserID,
|
||||
Issuer: writeModel.Issuer,
|
||||
ID: writeModel.AggregateID,
|
||||
LoginClient: writeModel.LoginClient,
|
||||
ClientID: writeModel.ClientID,
|
||||
RedirectURI: writeModel.RedirectURI,
|
||||
State: writeModel.State,
|
||||
Nonce: writeModel.Nonce,
|
||||
Scope: writeModel.Scope,
|
||||
Audience: writeModel.Audience,
|
||||
ResponseType: writeModel.ResponseType,
|
||||
ResponseMode: writeModel.ResponseMode,
|
||||
CodeChallenge: writeModel.CodeChallenge,
|
||||
Prompt: writeModel.Prompt,
|
||||
UILocales: writeModel.UILocales,
|
||||
MaxAge: writeModel.MaxAge,
|
||||
LoginHint: writeModel.LoginHint,
|
||||
HintUserID: writeModel.HintUserID,
|
||||
Issuer: writeModel.Issuer,
|
||||
OrganizationID: writeModel.OrganizationID,
|
||||
},
|
||||
SessionID: writeModel.SessionID,
|
||||
UserID: writeModel.UserID,
|
||||
|
||||
@@ -37,6 +37,7 @@ type AuthRequestWriteModel struct {
|
||||
AuthRequestState domain.AuthRequestState
|
||||
NeedRefreshToken bool
|
||||
Issuer string
|
||||
OrganizationID string
|
||||
}
|
||||
|
||||
func NewAuthRequestWriteModel(ctx context.Context, id string) *AuthRequestWriteModel {
|
||||
@@ -70,6 +71,7 @@ func (m *AuthRequestWriteModel) Reduce() error {
|
||||
m.AuthRequestState = domain.AuthRequestStateAdded
|
||||
m.NeedRefreshToken = e.NeedRefreshToken
|
||||
m.Issuer = e.Issuer
|
||||
m.OrganizationID = e.OrganizationID
|
||||
case *authrequest.SessionLinkedEvent:
|
||||
m.SessionID = e.SessionID
|
||||
m.UserID = e.UserID
|
||||
|
||||
@@ -63,6 +63,7 @@ func TestCommands_AddAuthRequest(t *testing.T) {
|
||||
nil,
|
||||
false,
|
||||
"issuer",
|
||||
"",
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -103,6 +104,7 @@ func TestCommands_AddAuthRequest(t *testing.T) {
|
||||
gu.Ptr("hintUserID"),
|
||||
false,
|
||||
"issuer",
|
||||
"organizationID",
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -124,12 +126,13 @@ func TestCommands_AddAuthRequest(t *testing.T) {
|
||||
Challenge: "challenge",
|
||||
Method: domain.CodeChallengeMethodS256,
|
||||
},
|
||||
Prompt: []domain.Prompt{domain.PromptNone},
|
||||
UILocales: []string{"en", "de"},
|
||||
MaxAge: gu.Ptr(time.Duration(0)),
|
||||
LoginHint: gu.Ptr("loginHint"),
|
||||
HintUserID: gu.Ptr("hintUserID"),
|
||||
Issuer: "issuer",
|
||||
Prompt: []domain.Prompt{domain.PromptNone},
|
||||
UILocales: []string{"en", "de"},
|
||||
MaxAge: gu.Ptr(time.Duration(0)),
|
||||
LoginHint: gu.Ptr("loginHint"),
|
||||
HintUserID: gu.Ptr("hintUserID"),
|
||||
Issuer: "issuer",
|
||||
OrganizationID: "organizationID",
|
||||
},
|
||||
},
|
||||
&CurrentAuthRequest{
|
||||
@@ -148,12 +151,13 @@ func TestCommands_AddAuthRequest(t *testing.T) {
|
||||
Challenge: "challenge",
|
||||
Method: domain.CodeChallengeMethodS256,
|
||||
},
|
||||
Prompt: []domain.Prompt{domain.PromptNone},
|
||||
UILocales: []string{"en", "de"},
|
||||
MaxAge: gu.Ptr(time.Duration(0)),
|
||||
LoginHint: gu.Ptr("loginHint"),
|
||||
HintUserID: gu.Ptr("hintUserID"),
|
||||
Issuer: "issuer",
|
||||
Prompt: []domain.Prompt{domain.PromptNone},
|
||||
UILocales: []string{"en", "de"},
|
||||
MaxAge: gu.Ptr(time.Duration(0)),
|
||||
LoginHint: gu.Ptr("loginHint"),
|
||||
HintUserID: gu.Ptr("hintUserID"),
|
||||
Issuer: "issuer",
|
||||
OrganizationID: "organizationID",
|
||||
},
|
||||
},
|
||||
nil,
|
||||
@@ -239,6 +243,7 @@ func TestCommands_LinkSessionToAuthRequest(t *testing.T) {
|
||||
nil,
|
||||
true,
|
||||
"issuer",
|
||||
"",
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
@@ -282,6 +287,7 @@ func TestCommands_LinkSessionToAuthRequest(t *testing.T) {
|
||||
nil,
|
||||
true,
|
||||
"issuer",
|
||||
"",
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -324,6 +330,7 @@ func TestCommands_LinkSessionToAuthRequest(t *testing.T) {
|
||||
nil,
|
||||
true,
|
||||
"issuer",
|
||||
"",
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -364,6 +371,7 @@ func TestCommands_LinkSessionToAuthRequest(t *testing.T) {
|
||||
nil,
|
||||
true,
|
||||
"issuer",
|
||||
"",
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -427,6 +435,7 @@ func TestCommands_LinkSessionToAuthRequest(t *testing.T) {
|
||||
nil,
|
||||
true,
|
||||
"issuer",
|
||||
"",
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -455,6 +464,71 @@ func TestCommands_LinkSessionToAuthRequest(t *testing.T) {
|
||||
wantErr: zerrors.ThrowPermissionDenied(nil, "COMMAND-sGr42", "Errors.Session.Token.Invalid"),
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid organization",
|
||||
fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
authrequest.NewAddedEvent(mockCtx, &authrequest.NewAggregate("V2_id", "instanceID").Aggregate,
|
||||
"loginClient",
|
||||
"clientID",
|
||||
"redirectURI",
|
||||
"state",
|
||||
"nonce",
|
||||
[]string{"openid"},
|
||||
[]string{"audience"},
|
||||
domain.OIDCResponseTypeCode,
|
||||
domain.OIDCResponseModeQuery,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
true,
|
||||
"issuer",
|
||||
"organizationID",
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
session.NewAddedEvent(mockCtx,
|
||||
&session.NewAggregate("sessionID", "instance1").Aggregate,
|
||||
&domain.UserAgent{
|
||||
FingerprintID: gu.Ptr("fp1"),
|
||||
IP: net.ParseIP("1.2.3.4"),
|
||||
Description: gu.Ptr("firefox"),
|
||||
Header: http.Header{"foo": []string{"bar"}},
|
||||
},
|
||||
)),
|
||||
eventFromEventPusher(
|
||||
session.NewUserCheckedEvent(mockCtx, &session.NewAggregate("sessionID", "instance1").Aggregate,
|
||||
"userID", "org1", testNow, &language.Afrikaans),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
session.NewPasswordCheckedEvent(mockCtx, &session.NewAggregate("sessionID", "instance1").Aggregate,
|
||||
testNow),
|
||||
),
|
||||
eventFromEventPusherWithCreationDateNow(
|
||||
session.NewLifetimeSetEvent(mockCtx, &session.NewAggregate("sessionID", "instance1").Aggregate,
|
||||
2*time.Minute),
|
||||
),
|
||||
),
|
||||
),
|
||||
tokenVerifier: newMockTokenVerifierValid(),
|
||||
},
|
||||
args{
|
||||
ctx: mockCtx,
|
||||
id: "V2_id",
|
||||
sessionID: "sessionID",
|
||||
sessionToken: "token",
|
||||
},
|
||||
res{
|
||||
wantErr: zerrors.ThrowPreconditionFailed(nil, "COMMAND-59ljd", "Errors.User.NotAllowedOrg"),
|
||||
},
|
||||
},
|
||||
{
|
||||
"linked",
|
||||
fields{
|
||||
@@ -479,6 +553,7 @@ func TestCommands_LinkSessionToAuthRequest(t *testing.T) {
|
||||
nil,
|
||||
true,
|
||||
"issuer",
|
||||
"",
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -545,6 +620,98 @@ func TestCommands_LinkSessionToAuthRequest(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"linked with organization check",
|
||||
fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
authrequest.NewAddedEvent(mockCtx, &authrequest.NewAggregate("V2_id", "instanceID").Aggregate,
|
||||
"loginClient",
|
||||
"clientID",
|
||||
"redirectURI",
|
||||
"state",
|
||||
"nonce",
|
||||
[]string{"openid"},
|
||||
[]string{"audience"},
|
||||
domain.OIDCResponseTypeCode,
|
||||
domain.OIDCResponseModeQuery,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
true,
|
||||
"issuer",
|
||||
"org1",
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
session.NewAddedEvent(mockCtx,
|
||||
&session.NewAggregate("sessionID", "instance1").Aggregate,
|
||||
&domain.UserAgent{
|
||||
FingerprintID: gu.Ptr("fp1"),
|
||||
IP: net.ParseIP("1.2.3.4"),
|
||||
Description: gu.Ptr("firefox"),
|
||||
Header: http.Header{"foo": []string{"bar"}},
|
||||
},
|
||||
)),
|
||||
eventFromEventPusher(
|
||||
session.NewUserCheckedEvent(mockCtx, &session.NewAggregate("sessionID", "instance1").Aggregate,
|
||||
"userID", "org1", testNow, &language.Afrikaans),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
session.NewPasswordCheckedEvent(mockCtx, &session.NewAggregate("sessionID", "instance1").Aggregate,
|
||||
testNow),
|
||||
),
|
||||
eventFromEventPusherWithCreationDateNow(
|
||||
session.NewLifetimeSetEvent(mockCtx, &session.NewAggregate("sessionID", "instance1").Aggregate,
|
||||
2*time.Minute),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
authrequest.NewSessionLinkedEvent(mockCtx, &authrequest.NewAggregate("V2_id", "instanceID").Aggregate,
|
||||
"sessionID",
|
||||
"userID",
|
||||
testNow,
|
||||
[]domain.UserAuthMethodType{domain.UserAuthMethodTypePassword},
|
||||
),
|
||||
),
|
||||
),
|
||||
tokenVerifier: newMockTokenVerifierValid(),
|
||||
},
|
||||
args{
|
||||
ctx: mockCtx,
|
||||
id: "V2_id",
|
||||
sessionID: "sessionID",
|
||||
sessionToken: "token",
|
||||
},
|
||||
res{
|
||||
details: &domain.ObjectDetails{ResourceOwner: "instanceID"},
|
||||
authReq: &CurrentAuthRequest{
|
||||
AuthRequest: &AuthRequest{
|
||||
ID: "V2_id",
|
||||
LoginClient: "loginClient",
|
||||
ClientID: "clientID",
|
||||
RedirectURI: "redirectURI",
|
||||
State: "state",
|
||||
Nonce: "nonce",
|
||||
Scope: []string{"openid"},
|
||||
Audience: []string{"audience"},
|
||||
ResponseType: domain.OIDCResponseTypeCode,
|
||||
ResponseMode: domain.OIDCResponseModeQuery,
|
||||
Issuer: "issuer",
|
||||
OrganizationID: "org1",
|
||||
},
|
||||
SessionID: "sessionID",
|
||||
UserID: "userID",
|
||||
AuthMethods: []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"linked with login client check",
|
||||
fields{
|
||||
@@ -569,6 +736,7 @@ func TestCommands_LinkSessionToAuthRequest(t *testing.T) {
|
||||
nil,
|
||||
true,
|
||||
"issuer",
|
||||
"",
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -660,6 +828,7 @@ func TestCommands_LinkSessionToAuthRequest(t *testing.T) {
|
||||
nil,
|
||||
true,
|
||||
"issuer",
|
||||
"",
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -752,6 +921,7 @@ func TestCommands_LinkSessionToAuthRequest(t *testing.T) {
|
||||
nil,
|
||||
true,
|
||||
"issuer",
|
||||
"",
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -845,6 +1015,7 @@ func TestCommands_LinkSessionToAuthRequest(t *testing.T) {
|
||||
nil,
|
||||
true,
|
||||
"issuer",
|
||||
"",
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -970,6 +1141,7 @@ func TestCommands_FailAuthRequest(t *testing.T) {
|
||||
nil,
|
||||
true,
|
||||
"issuer",
|
||||
"",
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -1009,6 +1181,7 @@ func TestCommands_FailAuthRequest(t *testing.T) {
|
||||
nil,
|
||||
true,
|
||||
"issuer",
|
||||
"",
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -1113,6 +1286,7 @@ func TestCommands_AddAuthRequestCode(t *testing.T) {
|
||||
gu.Ptr("hintUserID"),
|
||||
true,
|
||||
"issuer",
|
||||
"",
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -1152,6 +1326,7 @@ func TestCommands_AddAuthRequestCode(t *testing.T) {
|
||||
gu.Ptr("hintUserID"),
|
||||
true,
|
||||
"issuer",
|
||||
"",
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
func (c *Commands) AddDeviceAuth(ctx context.Context, clientID, deviceCode, userCode string, expires time.Time, scopes, audience []string, needRefreshToken bool) (*domain.ObjectDetails, error) {
|
||||
func (c *Commands) AddDeviceAuth(ctx context.Context, clientID, deviceCode, userCode, orgID string, expires time.Time, scopes, audience []string, needRefreshToken bool) (*domain.ObjectDetails, error) {
|
||||
aggr := deviceauth.NewAggregate(deviceCode, authz.GetInstance(ctx).InstanceID())
|
||||
model := NewDeviceAuthWriteModel(deviceCode, aggr.ResourceOwner)
|
||||
|
||||
@@ -29,6 +29,7 @@ func (c *Commands) AddDeviceAuth(ctx context.Context, clientID, deviceCode, user
|
||||
scopes,
|
||||
audience,
|
||||
needRefreshToken,
|
||||
orgID,
|
||||
))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -62,6 +63,9 @@ func (c *Commands) ApproveDeviceAuth(
|
||||
if model.State != domain.DeviceAuthStateInitiated {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-GEJL3", "Errors.DeviceAuth.AlreadyHandled")
|
||||
}
|
||||
if model.OrganizationID != "" && model.OrganizationID != userOrgID {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-3tgws", "Errors.User.NotAllowedOrg")
|
||||
}
|
||||
pushedEvents, err := c.eventstore.Push(ctx, deviceauth.NewApprovedEvent(ctx, model.aggregate, userID, userOrgID, authMethods, authTime, preferredLanguage, userAgent, sessionID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -105,6 +109,9 @@ func (c *Commands) ApproveDeviceAuthWithSession(
|
||||
if err := c.sessionTokenVerifier(ctx, sessionToken, sessionWriteModel.AggregateID, sessionWriteModel.TokenID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if model.OrganizationID != "" && model.OrganizationID != sessionWriteModel.UserResourceOwner {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-D2j34", "Errors.User.NotAllowedOrg")
|
||||
}
|
||||
|
||||
pushedEvents, err := c.eventstore.Push(ctx, deviceauth.NewApprovedEvent(
|
||||
ctx,
|
||||
|
||||
@@ -29,6 +29,7 @@ type DeviceAuthWriteModel struct {
|
||||
UserAgent *domain.UserAgent
|
||||
NeedRefreshToken bool
|
||||
SessionID string
|
||||
OrganizationID string
|
||||
}
|
||||
|
||||
func NewDeviceAuthWriteModel(deviceCode, resourceOwner string) *DeviceAuthWriteModel {
|
||||
@@ -53,6 +54,7 @@ func (m *DeviceAuthWriteModel) Reduce() error {
|
||||
m.Audience = e.Audience
|
||||
m.State = e.State
|
||||
m.NeedRefreshToken = e.NeedRefreshToken
|
||||
m.OrganizationID = e.OrganizationID
|
||||
case *deviceauth.ApprovedEvent:
|
||||
m.State = domain.DeviceAuthStateApproved
|
||||
m.UserID = e.UserID
|
||||
|
||||
@@ -49,6 +49,7 @@ func TestCommands_AddDeviceAuth(t *testing.T) {
|
||||
scopes []string
|
||||
audience []string
|
||||
needRefreshToken bool
|
||||
organizationID string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -66,7 +67,7 @@ func TestCommands_AddDeviceAuth(t *testing.T) {
|
||||
deviceauth.NewAggregate("123", "instance1"),
|
||||
"client_id", "123", "456", now,
|
||||
[]string{"a", "b", "c"},
|
||||
[]string{"projectID", "clientID"}, true,
|
||||
[]string{"projectID", "clientID"}, true, "orgID",
|
||||
),
|
||||
)),
|
||||
},
|
||||
@@ -79,6 +80,7 @@ func TestCommands_AddDeviceAuth(t *testing.T) {
|
||||
scopes: []string{"a", "b", "c"},
|
||||
audience: []string{"projectID", "clientID"},
|
||||
needRefreshToken: true,
|
||||
organizationID: "orgID",
|
||||
},
|
||||
wantDetails: &domain.ObjectDetails{
|
||||
ResourceOwner: "instance1",
|
||||
@@ -93,7 +95,7 @@ func TestCommands_AddDeviceAuth(t *testing.T) {
|
||||
deviceauth.NewAggregate("123", "instance1"),
|
||||
"client_id", "123", "456", now,
|
||||
[]string{"a", "b", "c"},
|
||||
[]string{"projectID", "clientID"}, false,
|
||||
[]string{"projectID", "clientID"}, false, "orgID",
|
||||
)),
|
||||
),
|
||||
},
|
||||
@@ -106,6 +108,7 @@ func TestCommands_AddDeviceAuth(t *testing.T) {
|
||||
scopes: []string{"a", "b", "c"},
|
||||
audience: []string{"projectID", "clientID"},
|
||||
needRefreshToken: false,
|
||||
organizationID: "orgID",
|
||||
},
|
||||
wantErr: pushErr,
|
||||
},
|
||||
@@ -115,7 +118,17 @@ func TestCommands_AddDeviceAuth(t *testing.T) {
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
}
|
||||
gotDetails, err := c.AddDeviceAuth(tt.args.ctx, tt.args.clientID, tt.args.deviceCode, tt.args.userCode, tt.args.expires, tt.args.scopes, tt.args.audience, tt.args.needRefreshToken)
|
||||
gotDetails, err := c.AddDeviceAuth(
|
||||
tt.args.ctx,
|
||||
tt.args.clientID,
|
||||
tt.args.deviceCode,
|
||||
tt.args.userCode,
|
||||
tt.args.organizationID,
|
||||
tt.args.expires,
|
||||
tt.args.scopes,
|
||||
tt.args.audience,
|
||||
tt.args.needRefreshToken,
|
||||
)
|
||||
require.ErrorIs(t, err, tt.wantErr)
|
||||
assertObjectDetails(t, tt.wantDetails, gotDetails)
|
||||
})
|
||||
@@ -168,6 +181,35 @@ func TestCommands_ApproveDeviceAuth(t *testing.T) {
|
||||
},
|
||||
wantErr: zerrors.ThrowNotFound(nil, "COMMAND-Hief9", "Errors.DeviceAuth.NotFound"),
|
||||
},
|
||||
{
|
||||
name: "invalid org",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(eventFromEventPusherWithInstanceID(
|
||||
"instance1",
|
||||
deviceauth.NewAddedEvent(
|
||||
ctx,
|
||||
deviceauth.NewAggregate("123", "instance1"),
|
||||
"client_id", "123", "456", now,
|
||||
[]string{"a", "b", "c"},
|
||||
[]string{"projectID", "clientID"}, true, "orgID2",
|
||||
),
|
||||
)),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx, "123", "subj", "orgID",
|
||||
[]domain.UserAuthMethodType{domain.UserAuthMethodTypePassword},
|
||||
time.Unix(123, 456), &language.Afrikaans, &domain.UserAgent{
|
||||
FingerprintID: gu.Ptr("fp1"),
|
||||
IP: net.ParseIP("1.2.3.4"),
|
||||
Description: gu.Ptr("firefox"),
|
||||
Header: http.Header{"foo": []string{"bar"}},
|
||||
},
|
||||
"sessionID",
|
||||
},
|
||||
wantErr: zerrors.ThrowPreconditionFailed(nil, "COMMAND-3tgws", "Errors.User.NotAllowedOrg"),
|
||||
},
|
||||
{
|
||||
name: "push error",
|
||||
fields: fields{
|
||||
@@ -179,7 +221,7 @@ func TestCommands_ApproveDeviceAuth(t *testing.T) {
|
||||
deviceauth.NewAggregate("123", "instance1"),
|
||||
"client_id", "123", "456", now,
|
||||
[]string{"a", "b", "c"},
|
||||
[]string{"projectID", "clientID"}, true,
|
||||
[]string{"projectID", "clientID"}, true, "",
|
||||
),
|
||||
)),
|
||||
expectPushFailed(pushErr,
|
||||
@@ -221,7 +263,51 @@ func TestCommands_ApproveDeviceAuth(t *testing.T) {
|
||||
deviceauth.NewAggregate("123", "instance1"),
|
||||
"client_id", "123", "456", now,
|
||||
[]string{"a", "b", "c"},
|
||||
[]string{"projectID", "clientID"}, true,
|
||||
[]string{"projectID", "clientID"}, true, "",
|
||||
),
|
||||
)),
|
||||
expectPush(
|
||||
deviceauth.NewApprovedEvent(
|
||||
ctx, deviceauth.NewAggregate("123", "instance1"), "subj", "orgID",
|
||||
[]domain.UserAuthMethodType{domain.UserAuthMethodTypePassword},
|
||||
time.Unix(123, 456), &language.Afrikaans, &domain.UserAgent{
|
||||
FingerprintID: gu.Ptr("fp1"),
|
||||
IP: net.ParseIP("1.2.3.4"),
|
||||
Description: gu.Ptr("firefox"),
|
||||
Header: http.Header{"foo": []string{"bar"}},
|
||||
},
|
||||
"sessionID",
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx, "123", "subj", "orgID",
|
||||
[]domain.UserAuthMethodType{domain.UserAuthMethodTypePassword},
|
||||
time.Unix(123, 456), &language.Afrikaans, &domain.UserAgent{
|
||||
FingerprintID: gu.Ptr("fp1"),
|
||||
IP: net.ParseIP("1.2.3.4"),
|
||||
Description: gu.Ptr("firefox"),
|
||||
Header: http.Header{"foo": []string{"bar"}},
|
||||
},
|
||||
"sessionID",
|
||||
},
|
||||
wantDetails: &domain.ObjectDetails{
|
||||
ResourceOwner: "instance1",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "success with organizationID in device auth",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(eventFromEventPusherWithInstanceID(
|
||||
"instance1",
|
||||
deviceauth.NewAddedEvent(
|
||||
ctx,
|
||||
deviceauth.NewAggregate("123", "instance1"),
|
||||
"client_id", "123", "456", now,
|
||||
[]string{"a", "b", "c"},
|
||||
[]string{"projectID", "clientID"}, true, "orgID",
|
||||
),
|
||||
)),
|
||||
expectPush(
|
||||
@@ -317,7 +403,7 @@ func TestCommands_ApproveDeviceAuthFromSession(t *testing.T) {
|
||||
deviceauth.NewAggregate("deviceCode", "instance1"),
|
||||
"client_id", "deviceCode", "456", now,
|
||||
[]string{"a", "b", "c"},
|
||||
[]string{"projectID", "clientID"}, true,
|
||||
[]string{"projectID", "clientID"}, true, "",
|
||||
),
|
||||
),
|
||||
eventFromEventPusherWithInstanceID(
|
||||
@@ -349,7 +435,7 @@ func TestCommands_ApproveDeviceAuthFromSession(t *testing.T) {
|
||||
deviceauth.NewAggregate("deviceCode", "instance1"),
|
||||
"client_id", "deviceCode", "456", now,
|
||||
[]string{"a", "b", "c"},
|
||||
[]string{"projectID", "clientID"}, true,
|
||||
[]string{"projectID", "clientID"}, true, "",
|
||||
),
|
||||
)),
|
||||
),
|
||||
@@ -374,7 +460,7 @@ func TestCommands_ApproveDeviceAuthFromSession(t *testing.T) {
|
||||
deviceauth.NewAggregate("deviceCode", "instance1"),
|
||||
"client_id", "deviceCode", "456", now,
|
||||
[]string{"a", "b", "c"},
|
||||
[]string{"projectID", "clientID"}, true,
|
||||
[]string{"projectID", "clientID"}, true, "",
|
||||
),
|
||||
)),
|
||||
expectFilter(),
|
||||
@@ -400,7 +486,7 @@ func TestCommands_ApproveDeviceAuthFromSession(t *testing.T) {
|
||||
deviceauth.NewAggregate("deviceCode", "instance1"),
|
||||
"client_id", "deviceCode", "456", now,
|
||||
[]string{"a", "b", "c"},
|
||||
[]string{"projectID", "clientID"}, true,
|
||||
[]string{"projectID", "clientID"}, true, "",
|
||||
),
|
||||
)),
|
||||
expectFilter(eventFromEventPusherWithInstanceID(
|
||||
@@ -426,6 +512,57 @@ func TestCommands_ApproveDeviceAuthFromSession(t *testing.T) {
|
||||
},
|
||||
wantErr: zerrors.ThrowPermissionDenied(nil, "COMMAND-sGr42", "Errors.Session.Token.Invalid"),
|
||||
},
|
||||
{
|
||||
name: "invalid organization, error",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(eventFromEventPusherWithInstanceID(
|
||||
"instance1",
|
||||
deviceauth.NewAddedEvent(
|
||||
ctx,
|
||||
deviceauth.NewAggregate("deviceCode", "instance1"),
|
||||
"client_id", "deviceCode", "456", now,
|
||||
[]string{"a", "b", "c"},
|
||||
[]string{"projectID", "clientID"}, true, "orgID2",
|
||||
),
|
||||
)),
|
||||
expectFilter(
|
||||
eventFromEventPusherWithInstanceID(
|
||||
"instance1",
|
||||
session.NewAddedEvent(ctx,
|
||||
&session.NewAggregate("sessionID", "instance1").Aggregate,
|
||||
&domain.UserAgent{
|
||||
FingerprintID: gu.Ptr("fp1"),
|
||||
IP: net.ParseIP("1.2.3.4"),
|
||||
Description: gu.Ptr("firefox"),
|
||||
Header: http.Header{"foo": []string{"bar"}},
|
||||
},
|
||||
)),
|
||||
eventFromEventPusher(
|
||||
session.NewUserCheckedEvent(ctx, &session.NewAggregate("sessionID", "instance1").Aggregate,
|
||||
"userID", "orgID", testNow, &language.Afrikaans),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
session.NewPasswordCheckedEvent(ctx, &session.NewAggregate("sessionID", "instance1").Aggregate,
|
||||
testNow),
|
||||
),
|
||||
eventFromEventPusherWithCreationDateNow(
|
||||
session.NewLifetimeSetEvent(ctx, &session.NewAggregate("sessionID", "instance1").Aggregate,
|
||||
2*time.Minute),
|
||||
),
|
||||
),
|
||||
),
|
||||
tokenVerifier: newMockTokenVerifierValid(),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx,
|
||||
"deviceCode",
|
||||
"sessionID",
|
||||
"sessionToken",
|
||||
},
|
||||
wantErr: zerrors.ThrowPreconditionFailed(nil, "COMMAND-D2j34", "Errors.User.NotAllowedOrg"),
|
||||
},
|
||||
{
|
||||
name: "push error",
|
||||
fields: fields{
|
||||
@@ -437,7 +574,7 @@ func TestCommands_ApproveDeviceAuthFromSession(t *testing.T) {
|
||||
deviceauth.NewAggregate("deviceCode", "instance1"),
|
||||
"client_id", "deviceCode", "456", now,
|
||||
[]string{"a", "b", "c"},
|
||||
[]string{"projectID", "clientID"}, true,
|
||||
[]string{"projectID", "clientID"}, true, "",
|
||||
),
|
||||
)),
|
||||
expectFilter(
|
||||
@@ -501,7 +638,73 @@ func TestCommands_ApproveDeviceAuthFromSession(t *testing.T) {
|
||||
deviceauth.NewAggregate("deviceCode", "instance1"),
|
||||
"client_id", "deviceCode", "456", now,
|
||||
[]string{"a", "b", "c"},
|
||||
[]string{"projectID", "clientID"}, true,
|
||||
[]string{"projectID", "clientID"}, true, "",
|
||||
),
|
||||
)),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
session.NewAddedEvent(ctx,
|
||||
&session.NewAggregate("sessionID", "instance1").Aggregate,
|
||||
&domain.UserAgent{
|
||||
FingerprintID: gu.Ptr("fp1"),
|
||||
IP: net.ParseIP("1.2.3.4"),
|
||||
Description: gu.Ptr("firefox"),
|
||||
Header: http.Header{"foo": []string{"bar"}},
|
||||
},
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
session.NewUserCheckedEvent(ctx, &session.NewAggregate("sessionID", "instance1").Aggregate,
|
||||
"userID", "orgID", testNow, &language.Afrikaans),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
session.NewPasswordCheckedEvent(ctx, &session.NewAggregate("sessionID", "instance1").Aggregate,
|
||||
testNow),
|
||||
),
|
||||
eventFromEventPusherWithCreationDateNow(
|
||||
session.NewLifetimeSetEvent(ctx, &session.NewAggregate("sessionID", "instance1").Aggregate,
|
||||
2*time.Minute),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
deviceauth.NewApprovedEvent(
|
||||
ctx, deviceauth.NewAggregate("deviceCode", "instance1"), "userID", "orgID",
|
||||
[]domain.UserAuthMethodType{domain.UserAuthMethodTypePassword},
|
||||
testNow, &language.Afrikaans, &domain.UserAgent{
|
||||
FingerprintID: gu.Ptr("fp1"),
|
||||
IP: net.ParseIP("1.2.3.4"),
|
||||
Description: gu.Ptr("firefox"),
|
||||
Header: http.Header{"foo": []string{"bar"}},
|
||||
},
|
||||
"sessionID",
|
||||
),
|
||||
),
|
||||
),
|
||||
tokenVerifier: newMockTokenVerifierValid(),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx,
|
||||
"deviceCode",
|
||||
"sessionID",
|
||||
"sessionToken",
|
||||
},
|
||||
wantDetails: &domain.ObjectDetails{
|
||||
ResourceOwner: "instance1",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "authorized with organizationID in device auth",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(eventFromEventPusherWithInstanceID(
|
||||
"instance1",
|
||||
deviceauth.NewAddedEvent(
|
||||
ctx,
|
||||
deviceauth.NewAggregate("deviceCode", "instance1"),
|
||||
"client_id", "deviceCode", "456", now,
|
||||
[]string{"a", "b", "c"},
|
||||
[]string{"projectID", "clientID"}, true, "orgID",
|
||||
),
|
||||
)),
|
||||
expectFilter(
|
||||
@@ -613,7 +816,7 @@ func TestCommands_CancelDeviceAuth(t *testing.T) {
|
||||
deviceauth.NewAggregate("123", "instance1"),
|
||||
"client_id", "123", "456", now,
|
||||
[]string{"a", "b", "c"},
|
||||
[]string{"projectID", "clientID"}, true,
|
||||
[]string{"projectID", "clientID"}, true, "",
|
||||
),
|
||||
)),
|
||||
),
|
||||
@@ -633,7 +836,7 @@ func TestCommands_CancelDeviceAuth(t *testing.T) {
|
||||
deviceauth.NewAggregate("123", "instance1"),
|
||||
"client_id", "123", "456", now,
|
||||
[]string{"a", "b", "c"},
|
||||
[]string{"projectID", "clientID"}, true,
|
||||
[]string{"projectID", "clientID"}, true, "",
|
||||
),
|
||||
)),
|
||||
expectPushFailed(pushErr,
|
||||
@@ -659,7 +862,7 @@ func TestCommands_CancelDeviceAuth(t *testing.T) {
|
||||
deviceauth.NewAggregate("123", "instance1"),
|
||||
"client_id", "123", "456", now,
|
||||
[]string{"a", "b", "c"},
|
||||
[]string{"projectID", "clientID"}, true,
|
||||
[]string{"projectID", "clientID"}, true, "",
|
||||
),
|
||||
)),
|
||||
expectPush(
|
||||
@@ -687,7 +890,7 @@ func TestCommands_CancelDeviceAuth(t *testing.T) {
|
||||
deviceauth.NewAggregate("123", "instance1"),
|
||||
"client_id", "123", "456", now,
|
||||
[]string{"a", "b", "c"},
|
||||
[]string{"projectID", "clientID"}, true,
|
||||
[]string{"projectID", "clientID"}, true, "",
|
||||
),
|
||||
)),
|
||||
expectPush(
|
||||
@@ -767,7 +970,7 @@ func TestCommands_CreateOIDCSessionFromDeviceAuth(t *testing.T) {
|
||||
deviceauth.NewAggregate("123", "instance1"),
|
||||
"clientID", "123", "456", time.Now().Add(time.Minute),
|
||||
[]string{"openid", "offline_access"},
|
||||
[]string{"audience"}, false,
|
||||
[]string{"audience"}, false, "",
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -806,7 +1009,7 @@ func TestCommands_CreateOIDCSessionFromDeviceAuth(t *testing.T) {
|
||||
deviceauth.NewAggregate("123", "instance1"),
|
||||
"clientID", "123", "456", time.Now().Add(-time.Minute),
|
||||
[]string{"openid", "offline_access"},
|
||||
[]string{"audience"}, false,
|
||||
[]string{"audience"}, false, "",
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -835,7 +1038,7 @@ func TestCommands_CreateOIDCSessionFromDeviceAuth(t *testing.T) {
|
||||
deviceauth.NewAggregate("123", "instance1"),
|
||||
"clientID", "123", "456", time.Now().Add(-time.Minute),
|
||||
[]string{"openid", "offline_access"},
|
||||
[]string{"audience"}, false,
|
||||
[]string{"audience"}, false, "",
|
||||
),
|
||||
),
|
||||
eventFromEventPusherWithInstanceID(
|
||||
@@ -867,7 +1070,7 @@ func TestCommands_CreateOIDCSessionFromDeviceAuth(t *testing.T) {
|
||||
deviceauth.NewAggregate("123", "instance1"),
|
||||
"clientID", "123", "456", time.Now().Add(-time.Minute),
|
||||
[]string{"openid", "offline_access"},
|
||||
[]string{"audience"}, false,
|
||||
[]string{"audience"}, false, "",
|
||||
),
|
||||
),
|
||||
eventFromEventPusherWithInstanceID(
|
||||
@@ -899,7 +1102,7 @@ func TestCommands_CreateOIDCSessionFromDeviceAuth(t *testing.T) {
|
||||
deviceauth.NewAggregate("123", "instance1"),
|
||||
"clientID", "123", "456", time.Now().Add(-time.Minute),
|
||||
[]string{"openid", "offline_access"},
|
||||
[]string{"audience"}, false,
|
||||
[]string{"audience"}, false, "",
|
||||
),
|
||||
),
|
||||
eventFromEventPusherWithInstanceID(
|
||||
@@ -937,7 +1140,7 @@ func TestCommands_CreateOIDCSessionFromDeviceAuth(t *testing.T) {
|
||||
deviceauth.NewAggregate("123", "instance1"),
|
||||
"clientID", "123", "456", time.Now().Add(-time.Minute),
|
||||
[]string{"openid", "offline_access"},
|
||||
[]string{"audience"}, false,
|
||||
[]string{"audience"}, false, "",
|
||||
),
|
||||
),
|
||||
eventFromEventPusherWithInstanceID(
|
||||
@@ -1001,7 +1204,7 @@ func TestCommands_CreateOIDCSessionFromDeviceAuth(t *testing.T) {
|
||||
deviceauth.NewAggregate("123", "instance1"),
|
||||
"clientID", "123", "456", time.Now().Add(-time.Minute),
|
||||
[]string{"openid", "offline_access"},
|
||||
[]string{"audience"}, false,
|
||||
[]string{"audience"}, false, "",
|
||||
),
|
||||
),
|
||||
eventFromEventPusherWithInstanceID(
|
||||
@@ -1098,7 +1301,7 @@ func TestCommands_CreateOIDCSessionFromDeviceAuth(t *testing.T) {
|
||||
deviceauth.NewAggregate("123", "instance1"),
|
||||
"clientID", "123", "456", time.Now().Add(-time.Minute),
|
||||
[]string{"openid", "offline_access"},
|
||||
[]string{"audience"}, false,
|
||||
[]string{"audience"}, false, "",
|
||||
),
|
||||
),
|
||||
eventFromEventPusherWithInstanceID(
|
||||
@@ -1202,7 +1405,7 @@ func TestCommands_CreateOIDCSessionFromDeviceAuth(t *testing.T) {
|
||||
deviceauth.NewAggregate("123", "instance1"),
|
||||
"clientID", "123", "456", time.Now().Add(-time.Minute),
|
||||
[]string{"openid", "offline_access"},
|
||||
[]string{"audience"}, true,
|
||||
[]string{"audience"}, true, "",
|
||||
),
|
||||
),
|
||||
eventFromEventPusherWithInstanceID(
|
||||
|
||||
@@ -138,6 +138,7 @@ func TestCommands_CreateOIDCSessionFromAuthRequest(t *testing.T) {
|
||||
gu.Ptr("hintUserID"),
|
||||
true,
|
||||
"issuer",
|
||||
"",
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
@@ -183,6 +184,7 @@ func TestCommands_CreateOIDCSessionFromAuthRequest(t *testing.T) {
|
||||
gu.Ptr("hintUserID"),
|
||||
true,
|
||||
"issuer",
|
||||
"",
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
@@ -236,6 +238,7 @@ func TestCommands_CreateOIDCSessionFromAuthRequest(t *testing.T) {
|
||||
gu.Ptr("hintUserID"),
|
||||
true,
|
||||
"issuer",
|
||||
"",
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
@@ -334,6 +337,7 @@ func TestCommands_CreateOIDCSessionFromAuthRequest(t *testing.T) {
|
||||
gu.Ptr("hintUserID"),
|
||||
true,
|
||||
"issuer",
|
||||
"",
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
@@ -468,6 +472,7 @@ func TestCommands_CreateOIDCSessionFromAuthRequest(t *testing.T) {
|
||||
gu.Ptr("hintUserID"),
|
||||
true,
|
||||
"issuer",
|
||||
"",
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
@@ -611,6 +616,7 @@ func TestCommands_CreateOIDCSessionFromAuthRequest(t *testing.T) {
|
||||
gu.Ptr("hintUserID"),
|
||||
false,
|
||||
"issuer",
|
||||
"",
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
|
||||
@@ -230,24 +230,18 @@ func (a *AuthRequest) AppendAudIfNotExisting(aud string) {
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetScopeOrgPrimaryDomain() string {
|
||||
switch request := a.Request.(type) {
|
||||
case *AuthRequestOIDC:
|
||||
for _, scope := range request.Scopes {
|
||||
if strings.HasPrefix(scope, OrgDomainPrimaryScope) {
|
||||
return strings.TrimPrefix(scope, OrgDomainPrimaryScope)
|
||||
}
|
||||
for _, scope := range a.Request.GetScopes() {
|
||||
if strings.HasPrefix(scope, OrgDomainPrimaryScope) {
|
||||
return strings.TrimPrefix(scope, OrgDomainPrimaryScope)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (a *AuthRequest) GetScopeOrgID() string {
|
||||
switch request := a.Request.(type) {
|
||||
case *AuthRequestOIDC:
|
||||
for _, scope := range request.Scopes {
|
||||
if strings.HasPrefix(scope, OrgIDScope) {
|
||||
return strings.TrimPrefix(scope, OrgIDScope)
|
||||
}
|
||||
for _, scope := range a.Request.GetScopes() {
|
||||
if strings.HasPrefix(scope, OrgIDScope) {
|
||||
return strings.TrimPrefix(scope, OrgIDScope)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
|
||||
@@ -17,6 +17,7 @@ const (
|
||||
type Request interface {
|
||||
Type() AuthRequestType
|
||||
IsValid() bool
|
||||
GetScopes() []string
|
||||
}
|
||||
|
||||
type AuthRequestType int32
|
||||
@@ -35,6 +36,18 @@ type AuthRequestOIDC struct {
|
||||
CodeChallenge *OIDCCodeChallenge
|
||||
}
|
||||
|
||||
func NewAuthRequestOIDC(
|
||||
scopes []string,
|
||||
responseType OIDCResponseType,
|
||||
responseMode OIDCResponseMode,
|
||||
nonce string,
|
||||
codeChallenge *OIDCCodeChallenge,
|
||||
) *AuthRequestOIDC {
|
||||
return &AuthRequestOIDC{
|
||||
scopes, responseType, responseMode, nonce, codeChallenge,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AuthRequestOIDC) Type() AuthRequestType {
|
||||
return AuthRequestTypeOIDC
|
||||
}
|
||||
@@ -44,6 +57,10 @@ func (a *AuthRequestOIDC) IsValid() bool {
|
||||
a.CodeChallenge == nil || a.CodeChallenge != nil && a.CodeChallenge.IsValid()
|
||||
}
|
||||
|
||||
func (a *AuthRequestOIDC) GetScopes() []string {
|
||||
return a.Scopes
|
||||
}
|
||||
|
||||
type AuthRequestSAML struct {
|
||||
ID string
|
||||
BindingType string
|
||||
@@ -61,6 +78,10 @@ func (a *AuthRequestSAML) IsValid() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (*AuthRequestSAML) GetScopes() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
type AuthRequestDevice struct {
|
||||
ClientID string
|
||||
DeviceCode string
|
||||
@@ -71,6 +92,20 @@ type AuthRequestDevice struct {
|
||||
ProjectName string
|
||||
}
|
||||
|
||||
func NewAuthRequestDevice(
|
||||
clientID string,
|
||||
deviceCode string,
|
||||
userCode string,
|
||||
scopes []string,
|
||||
audience []string,
|
||||
appName string,
|
||||
projectName string,
|
||||
) *AuthRequestDevice {
|
||||
return &AuthRequestDevice{
|
||||
clientID, deviceCode, userCode, scopes, audience, appName, projectName,
|
||||
}
|
||||
}
|
||||
|
||||
func (*AuthRequestDevice) Type() AuthRequestType {
|
||||
return AuthRequestTypeDevice
|
||||
}
|
||||
@@ -78,3 +113,7 @@ func (*AuthRequestDevice) Type() AuthRequestType {
|
||||
func (a *AuthRequestDevice) IsValid() bool {
|
||||
return a.DeviceCode != "" && a.UserCode != ""
|
||||
}
|
||||
|
||||
func (a *AuthRequestDevice) GetScopes() []string {
|
||||
return a.Scopes
|
||||
}
|
||||
|
||||
@@ -98,8 +98,10 @@ func prepareDeviceAuthQuery() (sq.SelectBuilder, func(*sql.Row) (*domain.AuthReq
|
||||
LeftJoin(join(ProjectColumnID, AppColumnProjectID)).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(row *sql.Row) (*domain.AuthRequestDevice, error) {
|
||||
dst := new(domain.AuthRequestDevice)
|
||||
var (
|
||||
clientID string
|
||||
deviceCode string
|
||||
userCode string
|
||||
scopes database.TextArray[string]
|
||||
audience database.TextArray[string]
|
||||
appName sql.NullString
|
||||
@@ -107,9 +109,9 @@ func prepareDeviceAuthQuery() (sq.SelectBuilder, func(*sql.Row) (*domain.AuthReq
|
||||
)
|
||||
|
||||
err := row.Scan(
|
||||
&dst.ClientID,
|
||||
&dst.DeviceCode,
|
||||
&dst.UserCode,
|
||||
&clientID,
|
||||
&deviceCode,
|
||||
&userCode,
|
||||
&scopes,
|
||||
&audience,
|
||||
&appName,
|
||||
@@ -121,11 +123,6 @@ func prepareDeviceAuthQuery() (sq.SelectBuilder, func(*sql.Row) (*domain.AuthReq
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInternal(err, "QUERY-Voo3o", "Errors.Internal")
|
||||
}
|
||||
dst.Scopes = scopes
|
||||
dst.Audience = audience
|
||||
dst.AppName = appName.String
|
||||
dst.ProjectName = projectName.String
|
||||
|
||||
return dst, nil
|
||||
return domain.NewAuthRequestDevice(clientID, deviceCode, userCode, scopes, audience, appName.String, projectName.String), nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,15 +52,15 @@ var (
|
||||
"appName",
|
||||
"projectName",
|
||||
}
|
||||
expectedDeviceAuth = &domain.AuthRequestDevice{
|
||||
ClientID: "client-id",
|
||||
DeviceCode: "device1",
|
||||
UserCode: "user-code",
|
||||
Scopes: []string{"a", "b", "c"},
|
||||
Audience: []string{"projectID", "clientID"},
|
||||
AppName: "appName",
|
||||
ProjectName: "projectName",
|
||||
}
|
||||
expectedDeviceAuth = domain.NewAuthRequestDevice(
|
||||
"client-id",
|
||||
"device1",
|
||||
"user-code",
|
||||
[]string{"a", "b", "c"},
|
||||
[]string{"projectID", "clientID"},
|
||||
"appName",
|
||||
"projectName",
|
||||
)
|
||||
)
|
||||
|
||||
func TestQueries_DeviceAuthRequestByUserCode(t *testing.T) {
|
||||
|
||||
@@ -39,6 +39,7 @@ type AddedEvent struct {
|
||||
HintUserID *string `json:"hint_user_id,omitempty"`
|
||||
NeedRefreshToken bool `json:"need_refresh_token,omitempty"`
|
||||
Issuer string `json:"issuer,omitempty"`
|
||||
OrganizationID string `json:"organization_id,omitempty"`
|
||||
}
|
||||
|
||||
func (e *AddedEvent) Payload() interface{} {
|
||||
@@ -67,7 +68,8 @@ func NewAddedEvent(ctx context.Context,
|
||||
loginHint,
|
||||
hintUserID *string,
|
||||
needRefreshToken bool,
|
||||
issuer string,
|
||||
issuer,
|
||||
organizationID string,
|
||||
) *AddedEvent {
|
||||
return &AddedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
@@ -92,6 +94,7 @@ func NewAddedEvent(ctx context.Context,
|
||||
HintUserID: hintUserID,
|
||||
NeedRefreshToken: needRefreshToken,
|
||||
Issuer: issuer,
|
||||
OrganizationID: organizationID,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ type AddedEvent struct {
|
||||
Audience []string
|
||||
State domain.DeviceAuthState
|
||||
NeedRefreshToken bool
|
||||
OrganizationID string
|
||||
}
|
||||
|
||||
func (e *AddedEvent) SetBaseEvent(b *eventstore.BaseEvent) {
|
||||
@@ -53,6 +54,7 @@ func NewAddedEvent(
|
||||
scopes []string,
|
||||
audience []string,
|
||||
needRefreshToken bool,
|
||||
organizationID string,
|
||||
) *AddedEvent {
|
||||
return &AddedEvent{
|
||||
eventstore.NewBaseEventForPush(
|
||||
@@ -60,6 +62,7 @@ func NewAddedEvent(
|
||||
),
|
||||
clientID, deviceCode, userCode, expires, scopes, audience,
|
||||
domain.DeviceAuthStateInitiated, needRefreshToken,
|
||||
organizationID,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user