fix: use of generic oauth provider (#5345)

Adds a id_attribute to the GenericOAuthProvider, which is used to map the external User. Further mapping can be done in actions by using the `rawInfo` of the new `ctx.v1.providerInfo` field.
This commit is contained in:
Livio Spring
2023-03-03 11:38:49 +01:00
committed by GitHub
parent cfe00ef0d0
commit 2efa305e10
28 changed files with 456 additions and 98 deletions

View File

@@ -16,6 +16,7 @@ type GenericOAuthProvider struct {
TokenEndpoint string
UserEndpoint string
Scopes []string
IDAttribute string
IDPOptions idp.Options
}

View File

@@ -21,6 +21,7 @@ type OAuthIDPWriteModel struct {
TokenEndpoint string
UserEndpoint string
Scopes []string
IDAttribute string
idp.Options
State domain.IDPState
@@ -48,6 +49,7 @@ func (wm *OAuthIDPWriteModel) reduceAddedEvent(e *idp.OAuthIDPAddedEvent) {
wm.TokenEndpoint = e.TokenEndpoint
wm.UserEndpoint = e.UserEndpoint
wm.Scopes = e.Scopes
wm.IDAttribute = e.IDAttribute
wm.State = domain.IDPStateActive
}
@@ -73,6 +75,9 @@ func (wm *OAuthIDPWriteModel) reduceChangedEvent(e *idp.OAuthIDPChangedEvent) {
if e.Scopes != nil {
wm.Scopes = e.Scopes
}
if e.IDAttribute != nil {
wm.IDAttribute = *e.IDAttribute
}
wm.Options.ReduceChanges(e.OptionChanges)
}
@@ -83,7 +88,8 @@ func (wm *OAuthIDPWriteModel) NewChanges(
secretCrypto crypto.Crypto,
authorizationEndpoint,
tokenEndpoint,
userEndpoint string,
userEndpoint,
idAttribute string,
scopes []string,
options idp.Options,
) ([]idp.OAuthIDPChanges, error) {
@@ -115,6 +121,9 @@ func (wm *OAuthIDPWriteModel) NewChanges(
if !reflect.DeepEqual(wm.Scopes, scopes) {
changes = append(changes, idp.ChangeOAuthScopes(scopes))
}
if wm.IDAttribute != idAttribute {
changes = append(changes, idp.ChangeOAuthIDAttribute(idAttribute))
}
opts := wm.Options.Changes(options)
if !opts.IsZero() {
changes = append(changes, idp.ChangeOAuthOptions(opts))

View File

@@ -273,6 +273,9 @@ func (c *Commands) prepareAddInstanceOAuthProvider(a *instance.Aggregate, writeM
if provider.UserEndpoint = strings.TrimSpace(provider.UserEndpoint); provider.UserEndpoint == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-Fb8jk", "Errors.Invalid.Argument")
}
if provider.IDAttribute = strings.TrimSpace(provider.IDAttribute); provider.IDAttribute == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-sdf3f", "Errors.Invalid.Argument")
}
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
events, err := filter(ctx, writeModel.Query())
if err != nil {
@@ -297,6 +300,7 @@ func (c *Commands) prepareAddInstanceOAuthProvider(a *instance.Aggregate, writeM
provider.AuthorizationEndpoint,
provider.TokenEndpoint,
provider.UserEndpoint,
provider.IDAttribute,
provider.Scopes,
provider.IDPOptions,
),
@@ -322,6 +326,9 @@ func (c *Commands) prepareUpdateInstanceOAuthProvider(a *instance.Aggregate, wri
if provider.UserEndpoint = strings.TrimSpace(provider.UserEndpoint); provider.UserEndpoint == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-Fb8jk", "Errors.Invalid.Argument")
}
if provider.IDAttribute = strings.TrimSpace(provider.IDAttribute); provider.IDAttribute == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-asf3fs", "Errors.Invalid.Argument")
}
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
events, err := filter(ctx, writeModel.Query())
if err != nil {
@@ -345,6 +352,7 @@ func (c *Commands) prepareUpdateInstanceOAuthProvider(a *instance.Aggregate, wri
provider.AuthorizationEndpoint,
provider.TokenEndpoint,
provider.UserEndpoint,
provider.IDAttribute,
provider.Scopes,
provider.IDPOptions,
)

View File

@@ -67,7 +67,8 @@ func (wm *InstanceOAuthIDPWriteModel) NewChangedEvent(
secretCrypto crypto.Crypto,
authorizationEndpoint,
tokenEndpoint,
userEndpoint string,
userEndpoint,
idAttribute string,
scopes []string,
options idp.Options,
) (*instance.OAuthIDPChangedEvent, error) {
@@ -80,6 +81,7 @@ func (wm *InstanceOAuthIDPWriteModel) NewChangedEvent(
authorizationEndpoint,
tokenEndpoint,
userEndpoint,
idAttribute,
scopes,
options,
)

View File

@@ -145,6 +145,27 @@ func TestCommandSide_AddInstanceGenericOAuthIDP(t *testing.T) {
err: caos_errors.IsErrorInvalidArgument,
},
},
{
"invalid id attribute",
fields{
eventstore: eventstoreExpect(t),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
},
args{
ctx: authz.WithInstanceID(context.Background(), "instance1"),
provider: GenericOAuthProvider{
Name: "name",
ClientID: "clientID",
ClientSecret: "clientSecret",
AuthorizationEndpoint: "auth",
TokenEndpoint: "token",
UserEndpoint: "user",
},
},
res{
err: caos_errors.IsErrorInvalidArgument,
},
},
{
name: "ok",
fields: fields{
@@ -167,6 +188,7 @@ func TestCommandSide_AddInstanceGenericOAuthIDP(t *testing.T) {
"auth",
"token",
"user",
"idAttribute",
nil,
idp.Options{},
)),
@@ -185,6 +207,7 @@ func TestCommandSide_AddInstanceGenericOAuthIDP(t *testing.T) {
AuthorizationEndpoint: "auth",
TokenEndpoint: "token",
UserEndpoint: "user",
IDAttribute: "idAttribute",
},
},
res: res{
@@ -214,6 +237,7 @@ func TestCommandSide_AddInstanceGenericOAuthIDP(t *testing.T) {
"auth",
"token",
"user",
"idAttribute",
[]string{"user"},
idp.Options{
IsCreationAllowed: true,
@@ -238,6 +262,7 @@ func TestCommandSide_AddInstanceGenericOAuthIDP(t *testing.T) {
TokenEndpoint: "token",
UserEndpoint: "user",
Scopes: []string{"user"},
IDAttribute: "idAttribute",
IDPOptions: idp.Options{
IsCreationAllowed: true,
IsLinkingAllowed: true,
@@ -390,6 +415,26 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) {
err: caos_errors.IsErrorInvalidArgument,
},
},
{
"invalid id attribute",
fields{
eventstore: eventstoreExpect(t),
},
args{
ctx: authz.WithInstanceID(context.Background(), "instance1"),
id: "id1",
provider: GenericOAuthProvider{
Name: "name",
ClientID: "clientID",
AuthorizationEndpoint: "auth",
TokenEndpoint: "token",
UserEndpoint: "user",
},
},
res{
err: caos_errors.IsErrorInvalidArgument,
},
},
{
name: "not found",
fields: fields{
@@ -406,6 +451,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) {
AuthorizationEndpoint: "auth",
TokenEndpoint: "token",
UserEndpoint: "user",
IDAttribute: "idAttribute",
},
},
res: res{
@@ -431,6 +477,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) {
"auth",
"token",
"user",
"idAttribute",
nil,
idp.Options{},
)),
@@ -446,6 +493,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) {
AuthorizationEndpoint: "auth",
TokenEndpoint: "token",
UserEndpoint: "user",
IDAttribute: "idAttribute",
},
},
res: res{
@@ -471,6 +519,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) {
"auth",
"token",
"user",
"idAttribute",
nil,
idp.Options{},
)),
@@ -496,6 +545,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) {
idp.ChangeOAuthTokenEndpoint("new token"),
idp.ChangeOAuthUserEndpoint("new user"),
idp.ChangeOAuthScopes([]string{"openid", "profile"}),
idp.ChangeOAuthIDAttribute("newAttribute"),
idp.ChangeOAuthOptions(idp.OptionChanges{
IsCreationAllowed: &t,
IsLinkingAllowed: &t,
@@ -523,6 +573,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) {
TokenEndpoint: "new token",
UserEndpoint: "new user",
Scopes: []string{"openid", "profile"},
IDAttribute: "newAttribute",
IDPOptions: idp.Options{
IsCreationAllowed: true,
IsLinkingAllowed: true,

View File

@@ -262,6 +262,9 @@ func (c *Commands) prepareAddOrgOAuthProvider(a *org.Aggregate, writeModel *OrgO
if provider.UserEndpoint = strings.TrimSpace(provider.UserEndpoint); provider.UserEndpoint == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-Fb8jk", "Errors.Invalid.Argument")
}
if provider.IDAttribute = strings.TrimSpace(provider.IDAttribute); provider.IDAttribute == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-sadf3d", "Errors.Invalid.Argument")
}
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
events, err := filter(ctx, writeModel.Query())
if err != nil {
@@ -286,6 +289,7 @@ func (c *Commands) prepareAddOrgOAuthProvider(a *org.Aggregate, writeModel *OrgO
provider.AuthorizationEndpoint,
provider.TokenEndpoint,
provider.UserEndpoint,
provider.IDAttribute,
provider.Scopes,
provider.IDPOptions,
),
@@ -314,6 +318,9 @@ func (c *Commands) prepareUpdateOrgOAuthProvider(a *org.Aggregate, writeModel *O
if provider.UserEndpoint = strings.TrimSpace(provider.UserEndpoint); provider.UserEndpoint == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-Fb8jk", "Errors.Invalid.Argument")
}
if provider.IDAttribute = strings.TrimSpace(provider.IDAttribute); provider.IDAttribute == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-SAe4gh", "Errors.Invalid.Argument")
}
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
events, err := filter(ctx, writeModel.Query())
if err != nil {
@@ -337,6 +344,7 @@ func (c *Commands) prepareUpdateOrgOAuthProvider(a *org.Aggregate, writeModel *O
provider.AuthorizationEndpoint,
provider.TokenEndpoint,
provider.UserEndpoint,
provider.IDAttribute,
provider.Scopes,
provider.IDPOptions,
)

View File

@@ -69,7 +69,8 @@ func (wm *OrgOAuthIDPWriteModel) NewChangedEvent(
secretCrypto crypto.Crypto,
authorizationEndpoint,
tokenEndpoint,
userEndpoint string,
userEndpoint,
idAttribute string,
scopes []string,
options idp.Options,
) (*org.OAuthIDPChangedEvent, error) {
@@ -82,6 +83,7 @@ func (wm *OrgOAuthIDPWriteModel) NewChangedEvent(
authorizationEndpoint,
tokenEndpoint,
userEndpoint,
idAttribute,
scopes,
options,
)

View File

@@ -150,6 +150,28 @@ func TestCommandSide_AddOrgGenericOAuthIDP(t *testing.T) {
err: caos_errors.IsErrorInvalidArgument,
},
},
{
"invalid id attribute",
fields{
eventstore: eventstoreExpect(t),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
},
args{
ctx: context.Background(),
resourceOwner: "org1",
provider: GenericOAuthProvider{
Name: "name",
ClientID: "clientID",
ClientSecret: "clientSecret",
AuthorizationEndpoint: "auth",
TokenEndpoint: "token",
UserEndpoint: "user",
},
},
res{
err: caos_errors.IsErrorInvalidArgument,
},
},
{
name: "ok",
fields: fields{
@@ -170,6 +192,7 @@ func TestCommandSide_AddOrgGenericOAuthIDP(t *testing.T) {
"auth",
"token",
"user",
"idAttribute",
nil,
idp.Options{},
)),
@@ -188,6 +211,7 @@ func TestCommandSide_AddOrgGenericOAuthIDP(t *testing.T) {
AuthorizationEndpoint: "auth",
TokenEndpoint: "token",
UserEndpoint: "user",
IDAttribute: "idAttribute",
},
},
res: res{
@@ -215,6 +239,7 @@ func TestCommandSide_AddOrgGenericOAuthIDP(t *testing.T) {
"auth",
"token",
"user",
"idAttribute",
[]string{"user"},
idp.Options{
IsCreationAllowed: true,
@@ -239,6 +264,7 @@ func TestCommandSide_AddOrgGenericOAuthIDP(t *testing.T) {
TokenEndpoint: "token",
UserEndpoint: "user",
Scopes: []string{"user"},
IDAttribute: "idAttribute",
IDPOptions: idp.Options{
IsCreationAllowed: true,
IsLinkingAllowed: true,
@@ -398,6 +424,27 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) {
err: caos_errors.IsErrorInvalidArgument,
},
},
{
"invalid id attribute",
fields{
eventstore: eventstoreExpect(t),
},
args{
ctx: context.Background(),
resourceOwner: "org1",
id: "id1",
provider: GenericOAuthProvider{
Name: "name",
ClientID: "clientID",
AuthorizationEndpoint: "auth",
TokenEndpoint: "token",
UserEndpoint: "user",
},
},
res{
err: caos_errors.IsErrorInvalidArgument,
},
},
{
name: "not found",
fields: fields{
@@ -415,6 +462,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) {
AuthorizationEndpoint: "auth",
TokenEndpoint: "token",
UserEndpoint: "user",
IDAttribute: "idAttribute",
},
},
res: res{
@@ -440,6 +488,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) {
"auth",
"token",
"user",
"idAttribute",
nil,
idp.Options{},
)),
@@ -456,6 +505,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) {
AuthorizationEndpoint: "auth",
TokenEndpoint: "token",
UserEndpoint: "user",
IDAttribute: "idAttribute",
},
},
res: res{
@@ -481,6 +531,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) {
"auth",
"token",
"user",
"idAttribute",
nil,
idp.Options{},
)),
@@ -504,6 +555,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) {
idp.ChangeOAuthTokenEndpoint("new token"),
idp.ChangeOAuthUserEndpoint("new user"),
idp.ChangeOAuthScopes([]string{"openid", "profile"}),
idp.ChangeOAuthIDAttribute("newAttribute"),
idp.ChangeOAuthOptions(idp.OptionChanges{
IsCreationAllowed: &t,
IsLinkingAllowed: &t,
@@ -531,6 +583,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) {
TokenEndpoint: "new token",
UserEndpoint: "new user",
Scopes: []string{"openid", "profile"},
IDAttribute: "newAttribute",
IDPOptions: idp.Options{
IsCreationAllowed: true,
IsLinkingAllowed: true,