Add assume org session on api

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2025-12-19 15:49:39 +01:00
parent 342d93911b
commit 3f0616530a
4 changed files with 931 additions and 35 deletions

View File

@@ -59,7 +59,7 @@ type Query {
}
type Mutation {
signIn(input: SignInInput!): SignInPayload! @session(required: NONE)
signIn(input: SignInInput!): SignInPayload! @session(required: OPTIONAL)
signUp(input: SignUpInput!): SignUpPayload! @session(required: NONE)
signOut: SignOutPayload! @session(required: PRESENT)
signUpFromInvitation(
@@ -75,6 +75,9 @@ type Mutation {
@session(required: PRESENT)
changeEmail(input: ChangeEmailInput!): ChangeEmailPayload!
@session(required: PRESENT)
assumeOrganizationSession(
input: AssumeOrganizationSessionInput!
): AssumeOrganizationSessionPayload! @session(required: PRESENT)
updateIdentityProfile(
input: UpdateIdentityProfileInput!
@@ -417,6 +420,12 @@ enum ProvisioningSource {
SAML
}
enum ReauthenticationReason {
SESSION_EXPIRED
SENSITIVE_ACTION
POLICY_REQUIREMENT
}
enum MembershipOrderField
@goModel(model: "go.probo.inc/probo/pkg/coredata.MembershipOrderField") {
ROLE
@@ -579,6 +588,10 @@ input ChangeEmailInput {
password: String!
}
input AssumeOrganizationSessionInput {
organizationId: ID!
}
input DeactivateAccountInput {
password: String!
}
@@ -709,6 +722,7 @@ input DeleteSAMLConfigurationInput {
type SignInPayload {
identity: Identity
session: Session
}
type SignUpPayload {
@@ -743,6 +757,29 @@ type ChangeEmailPayload {
success: Boolean!
}
union AssumeOrganizationSessionResult =
| OrganizationSessionCreated
| PasswordRequired
| SAMLAuthenticationRequired
type OrganizationSessionCreated {
session: Session!
membership: Membership!
}
type PasswordRequired {
reason: ReauthenticationReason!
}
type SAMLAuthenticationRequired {
reason: ReauthenticationReason!
redirectUrl: String!
}
type AssumeOrganizationSessionPayload {
result: AssumeOrganizationSessionResult!
}
type DeactivateAccountPayload {
success: Boolean!
}

View File

@@ -76,6 +76,10 @@ type ComplexityRoot struct {
Name func(childComplexity int) int
}
AssumeOrganizationSessionPayload struct {
Result func(childComplexity int) int
}
ChangeEmailPayload struct {
Success func(childComplexity int) int
}
@@ -215,6 +219,7 @@ type ComplexityRoot struct {
Mutation struct {
AcceptInvitation func(childComplexity int, input types.AcceptInvitationInput) int
AssumeOrganizationSession func(childComplexity int, input types.AssumeOrganizationSessionInput) int
ChangeEmail func(childComplexity int, input types.ChangeEmailInput) int
ChangePassword func(childComplexity int, input types.ChangePasswordInput) int
CreateOrganization func(childComplexity int, input types.CreateOrganizationInput) int
@@ -254,6 +259,11 @@ type ComplexityRoot struct {
UpdatedAt func(childComplexity int) int
}
OrganizationSessionCreated struct {
Membership func(childComplexity int) int
Session func(childComplexity int) int
}
PageInfo struct {
EndCursor func(childComplexity int) int
HasNextPage func(childComplexity int) int
@@ -261,6 +271,10 @@ type ComplexityRoot struct {
StartCursor func(childComplexity int) int
}
PasswordRequired struct {
Reason func(childComplexity int) int
}
Permission struct {
AccessLevel func(childComplexity int) int
Application func(childComplexity int) int
@@ -330,6 +344,11 @@ type ComplexityRoot struct {
Role func(childComplexity int) int
}
SAMLAuthenticationRequired struct {
Reason func(childComplexity int) int
RedirectURL func(childComplexity int) int
}
SAMLConfiguration struct {
AttributeMappings func(childComplexity int) int
AutoSignupEnabled func(childComplexity int) int
@@ -396,6 +415,7 @@ type ComplexityRoot struct {
SignInPayload struct {
Identity func(childComplexity int) int
Session func(childComplexity int) int
}
SignOutPayload struct {
@@ -462,6 +482,7 @@ type MutationResolver interface {
VerifyEmail(ctx context.Context, input types.VerifyEmailInput) (*types.VerifyEmailPayload, error)
ChangePassword(ctx context.Context, input types.ChangePasswordInput) (*types.ChangePasswordPayload, error)
ChangeEmail(ctx context.Context, input types.ChangeEmailInput) (*types.ChangeEmailPayload, error)
AssumeOrganizationSession(ctx context.Context, input types.AssumeOrganizationSessionInput) (*types.AssumeOrganizationSessionPayload, error)
UpdateIdentityProfile(ctx context.Context, input types.UpdateIdentityProfileInput) (*types.UpdateIdentityProfilePayload, error)
RevokeSession(ctx context.Context, input types.RevokeSessionInput) (*types.RevokeSessionPayload, error)
RevokeAllSessions(ctx context.Context) (*types.RevokeAllSessionsPayload, error)
@@ -553,6 +574,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.Application.Name(childComplexity), true
case "AssumeOrganizationSessionPayload.result":
if e.complexity.AssumeOrganizationSessionPayload.Result == nil {
break
}
return e.complexity.AssumeOrganizationSessionPayload.Result(childComplexity), true
case "ChangeEmailPayload.success":
if e.complexity.ChangeEmailPayload.Success == nil {
break
@@ -1054,6 +1082,17 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
}
return e.complexity.Mutation.AcceptInvitation(childComplexity, args["input"].(types.AcceptInvitationInput)), true
case "Mutation.assumeOrganizationSession":
if e.complexity.Mutation.AssumeOrganizationSession == nil {
break
}
args, err := ec.field_Mutation_assumeOrganizationSession_args(ctx, rawArgs)
if err != nil {
return 0, false
}
return e.complexity.Mutation.AssumeOrganizationSession(childComplexity, args["input"].(types.AssumeOrganizationSessionInput)), true
case "Mutation.changeEmail":
if e.complexity.Mutation.ChangeEmail == nil {
break
@@ -1385,6 +1424,19 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.Organization.UpdatedAt(childComplexity), true
case "OrganizationSessionCreated.membership":
if e.complexity.OrganizationSessionCreated.Membership == nil {
break
}
return e.complexity.OrganizationSessionCreated.Membership(childComplexity), true
case "OrganizationSessionCreated.session":
if e.complexity.OrganizationSessionCreated.Session == nil {
break
}
return e.complexity.OrganizationSessionCreated.Session(childComplexity), true
case "PageInfo.endCursor":
if e.complexity.PageInfo.EndCursor == nil {
break
@@ -1410,6 +1462,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.PageInfo.StartCursor(childComplexity), true
case "PasswordRequired.reason":
if e.complexity.PasswordRequired.Reason == nil {
break
}
return e.complexity.PasswordRequired.Reason(childComplexity), true
case "Permission.accessLevel":
if e.complexity.Permission.AccessLevel == nil {
break
@@ -1630,6 +1689,19 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.SAMLAttributeMappings.Role(childComplexity), true
case "SAMLAuthenticationRequired.reason":
if e.complexity.SAMLAuthenticationRequired.Reason == nil {
break
}
return e.complexity.SAMLAuthenticationRequired.Reason(childComplexity), true
case "SAMLAuthenticationRequired.redirectUrl":
if e.complexity.SAMLAuthenticationRequired.RedirectURL == nil {
break
}
return e.complexity.SAMLAuthenticationRequired.RedirectURL(childComplexity), true
case "SAMLConfiguration.attributeMappings":
if e.complexity.SAMLConfiguration.AttributeMappings == nil {
break
@@ -1884,6 +1956,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
}
return e.complexity.SignInPayload.Identity(childComplexity), true
case "SignInPayload.session":
if e.complexity.SignInPayload.Session == nil {
break
}
return e.complexity.SignInPayload.Session(childComplexity), true
case "SignOutPayload.success":
if e.complexity.SignOutPayload.Success == nil {
@@ -1951,6 +2029,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
inputUnmarshalMap := graphql.BuildUnmarshalerMap(
ec.unmarshalInputAcceptInvitationInput,
ec.unmarshalInputAddIPAllowlistEntryInput,
ec.unmarshalInputAssumeOrganizationSessionInput,
ec.unmarshalInputChangeEmailInput,
ec.unmarshalInputChangePasswordInput,
ec.unmarshalInputCreateOrganizationInput,
@@ -2139,7 +2218,7 @@ type Query {
}
type Mutation {
signIn(input: SignInInput!): SignInPayload! @session(required: NONE)
signIn(input: SignInInput!): SignInPayload! @session(required: OPTIONAL)
signUp(input: SignUpInput!): SignUpPayload! @session(required: NONE)
signOut: SignOutPayload! @session(required: PRESENT)
signUpFromInvitation(
@@ -2155,6 +2234,9 @@ type Mutation {
@session(required: PRESENT)
changeEmail(input: ChangeEmailInput!): ChangeEmailPayload!
@session(required: PRESENT)
assumeOrganizationSession(
input: AssumeOrganizationSessionInput!
): AssumeOrganizationSessionPayload! @session(required: PRESENT)
updateIdentityProfile(
input: UpdateIdentityProfileInput!
@@ -2497,6 +2579,12 @@ enum ProvisioningSource {
SAML
}
enum ReauthenticationReason {
SESSION_EXPIRED
SENSITIVE_ACTION
POLICY_REQUIREMENT
}
enum MembershipOrderField
@goModel(model: "go.probo.inc/probo/pkg/coredata.MembershipOrderField") {
ROLE
@@ -2659,6 +2747,10 @@ input ChangeEmailInput {
password: String!
}
input AssumeOrganizationSessionInput {
organizationId: ID!
}
input DeactivateAccountInput {
password: String!
}
@@ -2789,6 +2881,7 @@ input DeleteSAMLConfigurationInput {
type SignInPayload {
identity: Identity
session: Session
}
type SignUpPayload {
@@ -2823,6 +2916,29 @@ type ChangeEmailPayload {
success: Boolean!
}
union AssumeOrganizationSessionResult =
| OrganizationSessionCreated
| PasswordRequired
| SAMLAuthenticationRequired
type OrganizationSessionCreated {
session: Session!
membership: Membership!
}
type PasswordRequired {
reason: ReauthenticationReason!
}
type SAMLAuthenticationRequired {
reason: ReauthenticationReason!
redirectUrl: String!
}
type AssumeOrganizationSessionPayload {
result: AssumeOrganizationSessionResult!
}
type DeactivateAccountPayload {
success: Boolean!
}
@@ -3056,6 +3172,17 @@ func (ec *executionContext) field_Mutation_acceptInvitation_args(ctx context.Con
return args, nil
}
func (ec *executionContext) field_Mutation_assumeOrganizationSession_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error
args := map[string]any{}
arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNAssumeOrganizationSessionInput2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐAssumeOrganizationSessionInput)
if err != nil {
return nil, err
}
args["input"] = arg0
return args, nil
}
func (ec *executionContext) field_Mutation_changeEmail_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error
args := map[string]any{}
@@ -3617,6 +3744,35 @@ func (ec *executionContext) fieldContext_Application_availableAccessLevels(_ con
return fc, nil
}
func (ec *executionContext) _AssumeOrganizationSessionPayload_result(ctx context.Context, field graphql.CollectedField, obj *types.AssumeOrganizationSessionPayload) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
ec.OperationContext,
field,
ec.fieldContext_AssumeOrganizationSessionPayload_result,
func(ctx context.Context) (any, error) {
return obj.Result, nil
},
nil,
ec.marshalNAssumeOrganizationSessionResult2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐAssumeOrganizationSessionResult,
true,
true,
)
}
func (ec *executionContext) fieldContext_AssumeOrganizationSessionPayload_result(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "AssumeOrganizationSessionPayload",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type AssumeOrganizationSessionResult does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _ChangeEmailPayload_success(ctx context.Context, field graphql.CollectedField, obj *types.ChangeEmailPayload) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
@@ -6328,7 +6484,7 @@ func (ec *executionContext) _Mutation_signIn(ctx context.Context, field graphql.
directive0 := next
directive1 := func(ctx context.Context) (any, error) {
required, err := ec.unmarshalNSessionRequirement2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐSessionRequirement(ctx, "NONE")
required, err := ec.unmarshalNSessionRequirement2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐSessionRequirement(ctx, "OPTIONAL")
if err != nil {
var zeroVal *types.SignInPayload
return zeroVal, err
@@ -6359,6 +6515,8 @@ func (ec *executionContext) fieldContext_Mutation_signIn(ctx context.Context, fi
switch field.Name {
case "identity":
return ec.fieldContext_SignInPayload_identity(ctx, field)
case "session":
return ec.fieldContext_SignInPayload_session(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type SignInPayload", field.Name)
},
@@ -6869,6 +7027,69 @@ func (ec *executionContext) fieldContext_Mutation_changeEmail(ctx context.Contex
return fc, nil
}
func (ec *executionContext) _Mutation_assumeOrganizationSession(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
ec.OperationContext,
field,
ec.fieldContext_Mutation_assumeOrganizationSession,
func(ctx context.Context) (any, error) {
fc := graphql.GetFieldContext(ctx)
return ec.resolvers.Mutation().AssumeOrganizationSession(ctx, fc.Args["input"].(types.AssumeOrganizationSessionInput))
},
func(ctx context.Context, next graphql.Resolver) graphql.Resolver {
directive0 := next
directive1 := func(ctx context.Context) (any, error) {
required, err := ec.unmarshalNSessionRequirement2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐSessionRequirement(ctx, "PRESENT")
if err != nil {
var zeroVal *types.AssumeOrganizationSessionPayload
return zeroVal, err
}
if ec.directives.Session == nil {
var zeroVal *types.AssumeOrganizationSessionPayload
return zeroVal, errors.New("directive session is not implemented")
}
return ec.directives.Session(ctx, nil, directive0, required)
}
next = directive1
return next
},
ec.marshalNAssumeOrganizationSessionPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐAssumeOrganizationSessionPayload,
true,
true,
)
}
func (ec *executionContext) fieldContext_Mutation_assumeOrganizationSession(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Mutation",
Field: field,
IsMethod: true,
IsResolver: true,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "result":
return ec.fieldContext_AssumeOrganizationSessionPayload_result(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type AssumeOrganizationSessionPayload", field.Name)
},
}
defer func() {
if r := recover(); r != nil {
err = ec.Recover(ctx, r)
ec.Error(ctx, err)
}
}()
ctx = graphql.WithFieldContext(ctx, fc)
if fc.Args, err = ec.field_Mutation_assumeOrganizationSession_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
ec.Error(ctx, err)
return fc, err
}
return fc, nil
}
func (ec *executionContext) _Mutation_updateIdentityProfile(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
@@ -8229,6 +8450,102 @@ func (ec *executionContext) fieldContext_Organization_availableApplications(_ co
return fc, nil
}
func (ec *executionContext) _OrganizationSessionCreated_session(ctx context.Context, field graphql.CollectedField, obj *types.OrganizationSessionCreated) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
ec.OperationContext,
field,
ec.fieldContext_OrganizationSessionCreated_session,
func(ctx context.Context) (any, error) {
return obj.Session, nil
},
nil,
ec.marshalNSession2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐSession,
true,
true,
)
}
func (ec *executionContext) fieldContext_OrganizationSessionCreated_session(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "OrganizationSessionCreated",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "id":
return ec.fieldContext_Session_id(ctx, field)
case "ipAddress":
return ec.fieldContext_Session_ipAddress(ctx, field)
case "userAgent":
return ec.fieldContext_Session_userAgent(ctx, field)
case "updatedAt":
return ec.fieldContext_Session_updatedAt(ctx, field)
case "createdAt":
return ec.fieldContext_Session_createdAt(ctx, field)
case "expiresAt":
return ec.fieldContext_Session_expiresAt(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type Session", field.Name)
},
}
return fc, nil
}
func (ec *executionContext) _OrganizationSessionCreated_membership(ctx context.Context, field graphql.CollectedField, obj *types.OrganizationSessionCreated) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
ec.OperationContext,
field,
ec.fieldContext_OrganizationSessionCreated_membership,
func(ctx context.Context) (any, error) {
return obj.Membership, nil
},
nil,
ec.marshalNMembership2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐMembership,
true,
true,
)
}
func (ec *executionContext) fieldContext_OrganizationSessionCreated_membership(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "OrganizationSessionCreated",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "id":
return ec.fieldContext_Membership_id(ctx, field)
case "identityId":
return ec.fieldContext_Membership_identityId(ctx, field)
case "createdAt":
return ec.fieldContext_Membership_createdAt(ctx, field)
case "profile":
return ec.fieldContext_Membership_profile(ctx, field)
case "identity":
return ec.fieldContext_Membership_identity(ctx, field)
case "organization":
return ec.fieldContext_Membership_organization(ctx, field)
case "permissions":
return ec.fieldContext_Membership_permissions(ctx, field)
case "provisionedBy":
return ec.fieldContext_Membership_provisionedBy(ctx, field)
case "active":
return ec.fieldContext_Membership_active(ctx, field)
case "lastSyncedAt":
return ec.fieldContext_Membership_lastSyncedAt(ctx, field)
case "activeSession":
return ec.fieldContext_Membership_activeSession(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type Membership", field.Name)
},
}
return fc, nil
}
func (ec *executionContext) _PageInfo_hasNextPage(ctx context.Context, field graphql.CollectedField, obj *types.PageInfo) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
@@ -8345,6 +8662,35 @@ func (ec *executionContext) fieldContext_PageInfo_endCursor(_ context.Context, f
return fc, nil
}
func (ec *executionContext) _PasswordRequired_reason(ctx context.Context, field graphql.CollectedField, obj *types.PasswordRequired) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
ec.OperationContext,
field,
ec.fieldContext_PasswordRequired_reason,
func(ctx context.Context) (any, error) {
return obj.Reason, nil
},
nil,
ec.marshalNReauthenticationReason2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐReauthenticationReason,
true,
true,
)
}
func (ec *executionContext) fieldContext_PasswordRequired_reason(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "PasswordRequired",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type ReauthenticationReason does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _Permission_id(ctx context.Context, field graphql.CollectedField, obj *types.Permission) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
@@ -9614,6 +9960,64 @@ func (ec *executionContext) fieldContext_SAMLAttributeMappings_role(_ context.Co
return fc, nil
}
func (ec *executionContext) _SAMLAuthenticationRequired_reason(ctx context.Context, field graphql.CollectedField, obj *types.SAMLAuthenticationRequired) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
ec.OperationContext,
field,
ec.fieldContext_SAMLAuthenticationRequired_reason,
func(ctx context.Context) (any, error) {
return obj.Reason, nil
},
nil,
ec.marshalNReauthenticationReason2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐReauthenticationReason,
true,
true,
)
}
func (ec *executionContext) fieldContext_SAMLAuthenticationRequired_reason(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "SAMLAuthenticationRequired",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type ReauthenticationReason does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _SAMLAuthenticationRequired_redirectUrl(ctx context.Context, field graphql.CollectedField, obj *types.SAMLAuthenticationRequired) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
ec.OperationContext,
field,
ec.fieldContext_SAMLAuthenticationRequired_redirectUrl,
func(ctx context.Context) (any, error) {
return obj.RedirectURL, nil
},
nil,
ec.marshalNString2string,
true,
true,
)
}
func (ec *executionContext) fieldContext_SAMLAuthenticationRequired_redirectUrl(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "SAMLAuthenticationRequired",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type String does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _SAMLConfiguration_id(ctx context.Context, field graphql.CollectedField, obj *types.SAMLConfiguration) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
@@ -10923,6 +11327,49 @@ func (ec *executionContext) fieldContext_SignInPayload_identity(_ context.Contex
return fc, nil
}
func (ec *executionContext) _SignInPayload_session(ctx context.Context, field graphql.CollectedField, obj *types.SignInPayload) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
ec.OperationContext,
field,
ec.fieldContext_SignInPayload_session,
func(ctx context.Context) (any, error) {
return obj.Session, nil
},
nil,
ec.marshalOSession2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐSession,
true,
false,
)
}
func (ec *executionContext) fieldContext_SignInPayload_session(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "SignInPayload",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "id":
return ec.fieldContext_Session_id(ctx, field)
case "ipAddress":
return ec.fieldContext_Session_ipAddress(ctx, field)
case "userAgent":
return ec.fieldContext_Session_userAgent(ctx, field)
case "updatedAt":
return ec.fieldContext_Session_updatedAt(ctx, field)
case "createdAt":
return ec.fieldContext_Session_createdAt(ctx, field)
case "expiresAt":
return ec.fieldContext_Session_expiresAt(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type Session", field.Name)
},
}
return fc, nil
}
func (ec *executionContext) _SignOutPayload_success(ctx context.Context, field graphql.CollectedField, obj *types.SignOutPayload) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
@@ -12825,6 +13272,33 @@ func (ec *executionContext) unmarshalInputAddIPAllowlistEntryInput(ctx context.C
return it, nil
}
func (ec *executionContext) unmarshalInputAssumeOrganizationSessionInput(ctx context.Context, obj any) (types.AssumeOrganizationSessionInput, error) {
var it types.AssumeOrganizationSessionInput
asMap := map[string]any{}
for k, v := range obj.(map[string]any) {
asMap[k] = v
}
fieldsInOrder := [...]string{"organizationId"}
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
continue
}
switch k {
case "organizationId":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("organizationId"))
data, err := ec.unmarshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID(ctx, v)
if err != nil {
return it, err
}
it.OrganizationID = data
}
}
return it, nil
}
func (ec *executionContext) unmarshalInputChangeEmailInput(ctx context.Context, obj any) (types.ChangeEmailInput, error) {
var it types.ChangeEmailInput
asMap := map[string]any{}
@@ -14003,6 +14477,36 @@ func (ec *executionContext) unmarshalInputVerifyEmailInput(ctx context.Context,
// region ************************** interface.gotpl ***************************
func (ec *executionContext) _AssumeOrganizationSessionResult(ctx context.Context, sel ast.SelectionSet, obj types.AssumeOrganizationSessionResult) graphql.Marshaler {
switch obj := (obj).(type) {
case nil:
return graphql.Null
case types.SAMLAuthenticationRequired:
return ec._SAMLAuthenticationRequired(ctx, sel, &obj)
case *types.SAMLAuthenticationRequired:
if obj == nil {
return graphql.Null
}
return ec._SAMLAuthenticationRequired(ctx, sel, obj)
case types.PasswordRequired:
return ec._PasswordRequired(ctx, sel, &obj)
case *types.PasswordRequired:
if obj == nil {
return graphql.Null
}
return ec._PasswordRequired(ctx, sel, obj)
case types.OrganizationSessionCreated:
return ec._OrganizationSessionCreated(ctx, sel, &obj)
case *types.OrganizationSessionCreated:
if obj == nil {
return graphql.Null
}
return ec._OrganizationSessionCreated(ctx, sel, obj)
default:
panic(fmt.Errorf("unexpected type %T", obj))
}
}
func (ec *executionContext) _Node(ctx context.Context, sel ast.SelectionSet, obj types.Node) graphql.Marshaler {
switch obj := (obj).(type) {
case nil:
@@ -14172,6 +14676,45 @@ func (ec *executionContext) _Application(ctx context.Context, sel ast.SelectionS
return out
}
var assumeOrganizationSessionPayloadImplementors = []string{"AssumeOrganizationSessionPayload"}
func (ec *executionContext) _AssumeOrganizationSessionPayload(ctx context.Context, sel ast.SelectionSet, obj *types.AssumeOrganizationSessionPayload) graphql.Marshaler {
fields := graphql.CollectFields(ec.OperationContext, sel, assumeOrganizationSessionPayloadImplementors)
out := graphql.NewFieldSet(fields)
deferred := make(map[string]*graphql.FieldSet)
for i, field := range fields {
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("AssumeOrganizationSessionPayload")
case "result":
out.Values[i] = ec._AssumeOrganizationSessionPayload_result(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
default:
panic("unknown field " + strconv.Quote(field.Name))
}
}
out.Dispatch(ctx)
if out.Invalids > 0 {
return graphql.Null
}
atomic.AddInt32(&ec.deferred, int32(len(deferred)))
for label, dfs := range deferred {
ec.processDeferredGroup(graphql.DeferredGroup{
Label: label,
Path: graphql.GetPath(ctx),
FieldSet: dfs,
Context: ctx,
})
}
return out
}
var changeEmailPayloadImplementors = []string{"ChangeEmailPayload"}
func (ec *executionContext) _ChangeEmailPayload(ctx context.Context, sel ast.SelectionSet, obj *types.ChangeEmailPayload) graphql.Marshaler {
@@ -15603,6 +16146,13 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
if out.Values[i] == graphql.Null {
out.Invalids++
}
case "assumeOrganizationSession":
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_assumeOrganizationSession(ctx, field)
})
if out.Values[i] == graphql.Null {
out.Invalids++
}
case "updateIdentityProfile":
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_updateIdentityProfile(ctx, field)
@@ -15971,6 +16521,50 @@ func (ec *executionContext) _Organization(ctx context.Context, sel ast.Selection
return out
}
var organizationSessionCreatedImplementors = []string{"OrganizationSessionCreated", "AssumeOrganizationSessionResult"}
func (ec *executionContext) _OrganizationSessionCreated(ctx context.Context, sel ast.SelectionSet, obj *types.OrganizationSessionCreated) graphql.Marshaler {
fields := graphql.CollectFields(ec.OperationContext, sel, organizationSessionCreatedImplementors)
out := graphql.NewFieldSet(fields)
deferred := make(map[string]*graphql.FieldSet)
for i, field := range fields {
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("OrganizationSessionCreated")
case "session":
out.Values[i] = ec._OrganizationSessionCreated_session(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
case "membership":
out.Values[i] = ec._OrganizationSessionCreated_membership(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
default:
panic("unknown field " + strconv.Quote(field.Name))
}
}
out.Dispatch(ctx)
if out.Invalids > 0 {
return graphql.Null
}
atomic.AddInt32(&ec.deferred, int32(len(deferred)))
for label, dfs := range deferred {
ec.processDeferredGroup(graphql.DeferredGroup{
Label: label,
Path: graphql.GetPath(ctx),
FieldSet: dfs,
Context: ctx,
})
}
return out
}
var pageInfoImplementors = []string{"PageInfo"}
func (ec *executionContext) _PageInfo(ctx context.Context, sel ast.SelectionSet, obj *types.PageInfo) graphql.Marshaler {
@@ -16019,6 +16613,45 @@ func (ec *executionContext) _PageInfo(ctx context.Context, sel ast.SelectionSet,
return out
}
var passwordRequiredImplementors = []string{"PasswordRequired", "AssumeOrganizationSessionResult"}
func (ec *executionContext) _PasswordRequired(ctx context.Context, sel ast.SelectionSet, obj *types.PasswordRequired) graphql.Marshaler {
fields := graphql.CollectFields(ec.OperationContext, sel, passwordRequiredImplementors)
out := graphql.NewFieldSet(fields)
deferred := make(map[string]*graphql.FieldSet)
for i, field := range fields {
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("PasswordRequired")
case "reason":
out.Values[i] = ec._PasswordRequired_reason(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
default:
panic("unknown field " + strconv.Quote(field.Name))
}
}
out.Dispatch(ctx)
if out.Invalids > 0 {
return graphql.Null
}
atomic.AddInt32(&ec.deferred, int32(len(deferred)))
for label, dfs := range deferred {
ec.processDeferredGroup(graphql.DeferredGroup{
Label: label,
Path: graphql.GetPath(ctx),
FieldSet: dfs,
Context: ctx,
})
}
return out
}
var permissionImplementors = []string{"Permission", "Node"}
func (ec *executionContext) _Permission(ctx context.Context, sel ast.SelectionSet, obj *types.Permission) graphql.Marshaler {
@@ -16681,6 +17314,50 @@ func (ec *executionContext) _SAMLAttributeMappings(ctx context.Context, sel ast.
return out
}
var sAMLAuthenticationRequiredImplementors = []string{"SAMLAuthenticationRequired", "AssumeOrganizationSessionResult"}
func (ec *executionContext) _SAMLAuthenticationRequired(ctx context.Context, sel ast.SelectionSet, obj *types.SAMLAuthenticationRequired) graphql.Marshaler {
fields := graphql.CollectFields(ec.OperationContext, sel, sAMLAuthenticationRequiredImplementors)
out := graphql.NewFieldSet(fields)
deferred := make(map[string]*graphql.FieldSet)
for i, field := range fields {
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("SAMLAuthenticationRequired")
case "reason":
out.Values[i] = ec._SAMLAuthenticationRequired_reason(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
case "redirectUrl":
out.Values[i] = ec._SAMLAuthenticationRequired_redirectUrl(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
default:
panic("unknown field " + strconv.Quote(field.Name))
}
}
out.Dispatch(ctx)
if out.Invalids > 0 {
return graphql.Null
}
atomic.AddInt32(&ec.deferred, int32(len(deferred)))
for label, dfs := range deferred {
ec.processDeferredGroup(graphql.DeferredGroup{
Label: label,
Path: graphql.GetPath(ctx),
FieldSet: dfs,
Context: ctx,
})
}
return out
}
var sAMLConfigurationImplementors = []string{"SAMLConfiguration", "Node"}
func (ec *executionContext) _SAMLConfiguration(ctx context.Context, sel ast.SelectionSet, obj *types.SAMLConfiguration) graphql.Marshaler {
@@ -17213,6 +17890,8 @@ func (ec *executionContext) _SignInPayload(ctx context.Context, sel ast.Selectio
out.Values[i] = graphql.MarshalString("SignInPayload")
case "identity":
out.Values[i] = ec._SignInPayload_identity(ctx, field, obj)
case "session":
out.Values[i] = ec._SignInPayload_session(ctx, field, obj)
default:
panic("unknown field " + strconv.Quote(field.Name))
}
@@ -18017,6 +18696,35 @@ func (ec *executionContext) marshalNApplicationId2goᚗproboᚗincᚋproboᚋpkg
return v
}
func (ec *executionContext) unmarshalNAssumeOrganizationSessionInput2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐAssumeOrganizationSessionInput(ctx context.Context, v any) (types.AssumeOrganizationSessionInput, error) {
res, err := ec.unmarshalInputAssumeOrganizationSessionInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalNAssumeOrganizationSessionPayload2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐAssumeOrganizationSessionPayload(ctx context.Context, sel ast.SelectionSet, v types.AssumeOrganizationSessionPayload) graphql.Marshaler {
return ec._AssumeOrganizationSessionPayload(ctx, sel, &v)
}
func (ec *executionContext) marshalNAssumeOrganizationSessionPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐAssumeOrganizationSessionPayload(ctx context.Context, sel ast.SelectionSet, v *types.AssumeOrganizationSessionPayload) graphql.Marshaler {
if v == nil {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow")
}
return graphql.Null
}
return ec._AssumeOrganizationSessionPayload(ctx, sel, v)
}
func (ec *executionContext) marshalNAssumeOrganizationSessionResult2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐAssumeOrganizationSessionResult(ctx context.Context, sel ast.SelectionSet, v types.AssumeOrganizationSessionResult) graphql.Marshaler {
if v == nil {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow")
}
return graphql.Null
}
return ec._AssumeOrganizationSessionResult(ctx, sel, v)
}
func (ec *executionContext) unmarshalNBoolean2bool(ctx context.Context, v any) (bool, error) {
res, err := graphql.UnmarshalBoolean(v)
return res, graphql.ErrorOnPath(ctx, err)
@@ -18989,6 +19697,16 @@ func (ec *executionContext) marshalNProvisioningSource2goᚗproboᚗincᚋprobo
return v
}
func (ec *executionContext) unmarshalNReauthenticationReason2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐReauthenticationReason(ctx context.Context, v any) (types.ReauthenticationReason, error) {
var res types.ReauthenticationReason
err := res.UnmarshalGQL(v)
return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalNReauthenticationReason2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐReauthenticationReason(ctx context.Context, sel ast.SelectionSet, v types.ReauthenticationReason) graphql.Marshaler {
return v
}
func (ec *executionContext) unmarshalNRemoveMemberInput2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐRemoveMemberInput(ctx context.Context, v any) (types.RemoveMemberInput, error) {
res, err := ec.unmarshalInputRemoveMemberInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)

View File

@@ -16,6 +16,10 @@ import (
"go.probo.inc/probo/pkg/page"
)
type AssumeOrganizationSessionResult interface {
IsAssumeOrganizationSessionResult()
}
type Node interface {
IsNode()
GetID() gid.GID
@@ -42,6 +46,14 @@ type Application struct {
AvailableAccessLevels []AccessLevel `json:"availableAccessLevels"`
}
type AssumeOrganizationSessionInput struct {
OrganizationID gid.GID `json:"organizationId"`
}
type AssumeOrganizationSessionPayload struct {
Result AssumeOrganizationSessionResult `json:"result"`
}
type ChangeEmailInput struct {
NewEmail mail.Addr `json:"newEmail"`
Password string `json:"password"`
@@ -263,6 +275,13 @@ type Organization struct {
func (Organization) IsNode() {}
func (this Organization) GetID() gid.GID { return this.ID }
type OrganizationSessionCreated struct {
Session *Session `json:"session"`
Membership *Membership `json:"membership"`
}
func (OrganizationSessionCreated) IsAssumeOrganizationSessionResult() {}
type PageInfo struct {
HasNextPage bool `json:"hasNextPage"`
HasPreviousPage bool `json:"hasPreviousPage"`
@@ -270,6 +289,12 @@ type PageInfo struct {
EndCursor *page.CursorKey `json:"endCursor,omitempty"`
}
type PasswordRequired struct {
Reason ReauthenticationReason `json:"reason"`
}
func (PasswordRequired) IsAssumeOrganizationSessionResult() {}
type Permission struct {
ID gid.GID `json:"id"`
CreatedAt time.Time `json:"createdAt"`
@@ -365,6 +390,13 @@ type SAMLAttributeMappingsInput struct {
Role *string `json:"role,omitempty"`
}
type SAMLAuthenticationRequired struct {
Reason ReauthenticationReason `json:"reason"`
RedirectURL string `json:"redirectUrl"`
}
func (SAMLAuthenticationRequired) IsAssumeOrganizationSessionResult() {}
type SAMLConfiguration struct {
ID gid.GID `json:"id"`
EmailDomain string `json:"emailDomain"`
@@ -442,6 +474,7 @@ type SignInInput struct {
type SignInPayload struct {
Identity *Identity `json:"identity,omitempty"`
Session *Session `json:"session,omitempty"`
}
type SignOutPayload struct {
@@ -820,6 +853,63 @@ func (e ProvisioningSource) MarshalJSON() ([]byte, error) {
return buf.Bytes(), nil
}
type ReauthenticationReason string
const (
ReauthenticationReasonSessionExpired ReauthenticationReason = "SESSION_EXPIRED"
ReauthenticationReasonSensitiveAction ReauthenticationReason = "SENSITIVE_ACTION"
ReauthenticationReasonPolicyRequirement ReauthenticationReason = "POLICY_REQUIREMENT"
)
var AllReauthenticationReason = []ReauthenticationReason{
ReauthenticationReasonSessionExpired,
ReauthenticationReasonSensitiveAction,
ReauthenticationReasonPolicyRequirement,
}
func (e ReauthenticationReason) IsValid() bool {
switch e {
case ReauthenticationReasonSessionExpired, ReauthenticationReasonSensitiveAction, ReauthenticationReasonPolicyRequirement:
return true
}
return false
}
func (e ReauthenticationReason) String() string {
return string(e)
}
func (e *ReauthenticationReason) UnmarshalGQL(v any) error {
str, ok := v.(string)
if !ok {
return fmt.Errorf("enums must be strings")
}
*e = ReauthenticationReason(str)
if !e.IsValid() {
return fmt.Errorf("%s is not a valid ReauthenticationReason", str)
}
return nil
}
func (e ReauthenticationReason) MarshalGQL(w io.Writer) {
fmt.Fprint(w, strconv.Quote(e.String()))
}
func (e *ReauthenticationReason) UnmarshalJSON(b []byte) error {
s, err := strconv.Unquote(string(b))
if err != nil {
return err
}
return e.UnmarshalGQL(s)
}
func (e ReauthenticationReason) MarshalJSON() ([]byte, error) {
var buf bytes.Buffer
e.MarshalGQL(&buf)
return buf.Bytes(), nil
}
type SessionRequirement string
const (

View File

@@ -215,13 +215,8 @@ func (r *mutationResolver) SignIn(ctx context.Context, input types.SignInInput)
)
return &types.SignInPayload{
Identity: &types.Identity{
ID: user.ID,
Email: user.EmailAddress,
EmailVerified: user.EmailAddressVerified,
CreatedAt: user.CreatedAt,
UpdatedAt: user.UpdatedAt,
},
Identity: types.NewIdentity(user),
Session: types.NewSession(session),
}, nil
}
@@ -465,6 +460,50 @@ func (r *mutationResolver) ChangeEmail(ctx context.Context, input types.ChangeEm
}, nil
}
// AssumeOrganizationSession is the resolver for the assumeOrganizationSession field.
func (r *mutationResolver) AssumeOrganizationSession(ctx context.Context, input types.AssumeOrganizationSessionInput) (*types.AssumeOrganizationSessionPayload, error) {
rootSession := SessionFromContext(ctx)
childSession, membership, err := r.iam.SessionService.AssumeOrganizationSession(ctx, rootSession.ID, input.OrganizationID)
if err != nil {
var (
errMembershipNotFound *iam.ErrMembershipNotFound
errPasswordRequired *iam.ErrPasswordRequired
errSAMLAuthenticationRequired *iam.ErrSAMLAuthenticationRequired
)
switch {
case errors.As(err, &errMembershipNotFound):
return nil, gqlutils.NotFound(err)
case errors.As(err, &errPasswordRequired):
return &types.AssumeOrganizationSessionPayload{
Result: types.PasswordRequired{
Reason: types.ReauthenticationReason(errPasswordRequired.Reason),
},
}, nil
case errors.As(err, &errSAMLAuthenticationRequired):
return &types.AssumeOrganizationSessionPayload{
Result: types.SAMLAuthenticationRequired{
Reason: types.ReauthenticationReason(errSAMLAuthenticationRequired.Reason),
RedirectURL: errSAMLAuthenticationRequired.RedirectURL,
},
}, nil
default:
panic(fmt.Errorf("cannot assume organization session: %w", err))
}
}
return &types.AssumeOrganizationSessionPayload{
Result: types.OrganizationSessionCreated{
Session: types.NewSession(childSession),
Membership: types.NewMembership(membership),
},
}, nil
}
// UpdateIdentityProfile is the resolver for the updateIdentityProfile field.
func (r *mutationResolver) UpdateIdentityProfile(ctx context.Context, input types.UpdateIdentityProfileInput) (*types.UpdateIdentityProfilePayload, error) {
panic(fmt.Errorf("not implemented: UpdateIdentityProfile - updateIdentityProfile"))
@@ -1061,3 +1100,15 @@ type personalAPIKeyConnectionResolver struct{ *Resolver }
type queryResolver struct{ *Resolver }
type sAMLConfigurationConnectionResolver struct{ *Resolver }
type sessionConnectionResolver struct{ *Resolver }
// !!! WARNING !!!
// The code below was going to be deleted when updating resolvers. It has been copied here so you have
// one last chance to move it out of harms way if you want. There are two reasons this happens:
// - When renaming or deleting a resolver the old code will be put in here. You can safely delete
// it when you're done.
// - You have helper methods in this file. Move them out to keep these resolver files clean.
/*
func (r *mutationResolver) SignInWithSession(ctx context.Context, input types.SignInWithSessionInput) (*types.SignInWithSessionPayload, error) {
panic(fmt.Errorf("not implemented: SignInWithSession - signInWithSession"))
}
*/