feat: jwt as idp (#2363)

* feat: jwt idp

* feat: command side

* feat: add tests

* fill idp views with jwt idps and return apis

* add jwtEndpoint to jwt idp

* begin jwt request handling

* merge

* handle jwt idp

* cleanup

* fixes

* autoregister

* get token from specific header name

* error handling

* fix texts

* handle renderExternalNotFoundOption

Co-authored-by: fabi <fabienne.gerschwiler@gmail.com>
This commit is contained in:
Livio Amstutz
2021-09-14 15:15:01 +02:00
committed by GitHub
parent 4e1d42259c
commit b6b5b1b782
54 changed files with 2575 additions and 71 deletions

View File

@@ -42,6 +42,21 @@ func (s *Server) AddOIDCIDP(ctx context.Context, req *admin_pb.AddOIDCIDPRequest
}, nil
}
func (s *Server) AddJWTIDP(ctx context.Context, req *admin_pb.AddJWTIDPRequest) (*admin_pb.AddJWTIDPResponse, error) {
config, err := s.command.AddDefaultIDPConfig(ctx, addJWTIDPRequestToDomain(req))
if err != nil {
return nil, err
}
return &admin_pb.AddJWTIDPResponse{
IdpId: config.IDPConfigID,
Details: object_pb.AddToDetailsPb(
config.Sequence,
config.ChangeDate,
config.ResourceOwner,
),
}, nil
}
func (s *Server) UpdateIDP(ctx context.Context, req *admin_pb.UpdateIDPRequest) (*admin_pb.UpdateIDPResponse, error) {
config, err := s.command.ChangeDefaultIDPConfig(ctx, updateIDPToDomain(req))
if err != nil {
@@ -101,3 +116,17 @@ func (s *Server) UpdateIDPOIDCConfig(ctx context.Context, req *admin_pb.UpdateID
),
}, nil
}
func (s *Server) UpdateIDPJWTConfig(ctx context.Context, req *admin_pb.UpdateIDPJWTConfigRequest) (*admin_pb.UpdateIDPJWTConfigResponse, error) {
config, err := s.command.ChangeDefaultIDPJWTConfig(ctx, updateJWTConfigToDomain(req))
if err != nil {
return nil, err
}
return &admin_pb.UpdateIDPJWTConfigResponse{
Details: object_pb.ChangeToDetailsPb(
config.Sequence,
config.ChangeDate,
config.ResourceOwner,
),
}, nil
}

View File

@@ -31,6 +31,25 @@ func addOIDCIDPRequestToDomainOIDCIDPConfig(req *admin_pb.AddOIDCIDPRequest) *do
}
}
func addJWTIDPRequestToDomain(req *admin_pb.AddJWTIDPRequest) *domain.IDPConfig {
return &domain.IDPConfig{
Name: req.Name,
JWTConfig: addJWTIDPRequestToDomainJWTIDPConfig(req),
StylingType: idp_grpc.IDPStylingTypeToDomain(req.StylingType),
Type: domain.IDPConfigTypeJWT,
AutoRegister: req.AutoRegister,
}
}
func addJWTIDPRequestToDomainJWTIDPConfig(req *admin_pb.AddJWTIDPRequest) *domain.JWTIDPConfig {
return &domain.JWTIDPConfig{
JWTEndpoint: req.JwtEndpoint,
Issuer: req.Issuer,
KeysEndpoint: req.KeysEndpoint,
HeaderName: req.HeaderName,
}
}
func updateIDPToDomain(req *admin_pb.UpdateIDPRequest) *domain.IDPConfig {
return &domain.IDPConfig{
IDPConfigID: req.IdpId,
@@ -52,6 +71,16 @@ func updateOIDCConfigToDomain(req *admin_pb.UpdateIDPOIDCConfigRequest) *domain.
}
}
func updateJWTConfigToDomain(req *admin_pb.UpdateIDPJWTConfigRequest) *domain.JWTIDPConfig {
return &domain.JWTIDPConfig{
IDPConfigID: req.IdpId,
JWTEndpoint: req.JwtEndpoint,
Issuer: req.Issuer,
KeysEndpoint: req.KeysEndpoint,
HeaderName: req.HeaderName,
}
}
func listIDPsToModel(req *admin_pb.ListIDPsRequest) *iam_model.IDPConfigSearchRequest {
offset, limit, asc := object.ListQueryToModel(req.Query)
return &iam_model.IDPConfigSearchRequest{

View File

@@ -46,6 +46,7 @@ func Test_addOIDCIDPRequestToDomain(t *testing.T) {
"OIDCConfig.AuthorizationEndpoint",
"OIDCConfig.TokenEndpoint",
"Type", //TODO: default (0) is oidc
"JWTConfig",
)
})
}
@@ -113,6 +114,7 @@ func Test_updateIDPToDomain(t *testing.T) {
test.AssertFieldsMapped(t, got,
"ObjectRoot",
"OIDCConfig",
"JWTConfig",
"State",
"Type", //TODO: type should not be changeable
)

View File

@@ -59,7 +59,7 @@ func ExternalIDPViewToLoginPolicyLinkPb(link *iam_model.IDPProviderView) *idp_pb
return &idp_pb.IDPLoginPolicyLink{
IdpId: link.IDPConfigID,
IdpName: link.Name,
IdpType: idp_pb.IDPType_IDP_TYPE_OIDC,
IdpType: IDPTypeToPb(link.IDPConfigType),
}
}
@@ -79,7 +79,20 @@ func ExternalIDPViewToUserLinkPb(link *user_model.ExternalIDPView) *idp_pb.IDPUs
ProvidedUserId: link.ExternalUserID,
ProvidedUserName: link.UserDisplayName,
//TODO: as soon as saml is implemented we need to switch here
IdpType: idp_pb.IDPType_IDP_TYPE_OIDC,
//IdpType: IDPTypeToPb(link.Type),
}
}
func IDPTypeToPb(idpType iam_model.IdpConfigType) idp_pb.IDPType {
switch idpType {
case iam_model.IDPConfigTypeOIDC:
return idp_pb.IDPType_IDP_TYPE_OIDC
case iam_model.IDPConfigTypeSAML:
return idp_pb.IDPType_IDP_TYPE_UNSPECIFIED
case iam_model.IDPConfigTypeJWT:
return idp_pb.IDPType_IDP_TYPE_JWT
default:
return idp_pb.IDPType_IDP_TYPE_UNSPECIFIED
}
}
@@ -132,26 +145,45 @@ func IDPStylingTypeToPb(stylingType domain.IDPConfigStylingType) idp_pb.IDPStyli
}
}
func ModelIDPViewToConfigPb(config *iam_model.IDPConfigView) *idp_pb.IDP_OidcConfig {
return &idp_pb.IDP_OidcConfig{
OidcConfig: &idp_pb.OIDCConfig{
ClientId: config.OIDCClientID,
Issuer: config.OIDCIssuer,
Scopes: config.OIDCScopes,
DisplayNameMapping: ModelMappingFieldToPb(config.OIDCIDPDisplayNameMapping),
UsernameMapping: ModelMappingFieldToPb(config.OIDCUsernameMapping),
func ModelIDPViewToConfigPb(config *iam_model.IDPConfigView) idp_pb.IDPConfig {
if config.IsOIDC {
return &idp_pb.IDP_OidcConfig{
OidcConfig: &idp_pb.OIDCConfig{
ClientId: config.OIDCClientID,
Issuer: config.OIDCIssuer,
Scopes: config.OIDCScopes,
DisplayNameMapping: ModelMappingFieldToPb(config.OIDCIDPDisplayNameMapping),
UsernameMapping: ModelMappingFieldToPb(config.OIDCUsernameMapping),
},
}
}
return &idp_pb.IDP_JwtConfig{
JwtConfig: &idp_pb.JWTConfig{
JwtEndpoint: config.JWTEndpoint,
Issuer: config.JWTIssuer,
KeysEndpoint: config.JWTKeysEndpoint,
HeaderName: config.JWTHeaderName,
},
}
}
func IDPViewToConfigPb(config *domain.IDPConfigView) *idp_pb.IDP_OidcConfig {
return &idp_pb.IDP_OidcConfig{
OidcConfig: &idp_pb.OIDCConfig{
ClientId: config.OIDCClientID,
Issuer: config.OIDCIssuer,
Scopes: config.OIDCScopes,
DisplayNameMapping: MappingFieldToPb(config.OIDCIDPDisplayNameMapping),
UsernameMapping: MappingFieldToPb(config.OIDCUsernameMapping),
func IDPViewToConfigPb(config *domain.IDPConfigView) idp_pb.IDPConfig {
if config.IsOIDC {
return &idp_pb.IDP_OidcConfig{
OidcConfig: &idp_pb.OIDCConfig{
ClientId: config.OIDCClientID,
Issuer: config.OIDCIssuer,
Scopes: config.OIDCScopes,
DisplayNameMapping: MappingFieldToPb(config.OIDCIDPDisplayNameMapping),
UsernameMapping: MappingFieldToPb(config.OIDCUsernameMapping),
},
}
}
return &idp_pb.IDP_JwtConfig{
JwtConfig: &idp_pb.JWTConfig{
JwtEndpoint: config.JWTEndpoint,
Issuer: config.JWTIssuer,
KeysEndpoint: config.JWTKeysEndpoint,
},
}
}

View File

@@ -40,6 +40,22 @@ func (s *Server) AddOrgOIDCIDP(ctx context.Context, req *mgmt_pb.AddOrgOIDCIDPRe
),
}, nil
}
func (s *Server) AddOrgJWTIDP(ctx context.Context, req *mgmt_pb.AddOrgJWTIDPRequest) (*mgmt_pb.AddOrgJWTIDPResponse, error) {
config, err := s.command.AddIDPConfig(ctx, addJWTIDPRequestToDomain(req), authz.GetCtxData(ctx).OrgID)
if err != nil {
return nil, err
}
return &mgmt_pb.AddOrgJWTIDPResponse{
IdpId: config.IDPConfigID,
Details: object_pb.AddToDetailsPb(
config.Sequence,
config.ChangeDate,
config.ResourceOwner,
),
}, nil
}
func (s *Server) DeactivateOrgIDP(ctx context.Context, req *mgmt_pb.DeactivateOrgIDPRequest) (*mgmt_pb.DeactivateOrgIDPResponse, error) {
objectDetails, err := s.command.DeactivateIDPConfig(ctx, req.IdpId, authz.GetCtxData(ctx).OrgID)
if err != nil {
@@ -96,3 +112,17 @@ func (s *Server) UpdateOrgIDPOIDCConfig(ctx context.Context, req *mgmt_pb.Update
),
}, nil
}
func (s *Server) UpdateOrgIDPJWTConfig(ctx context.Context, req *mgmt_pb.UpdateOrgIDPJWTConfigRequest) (*mgmt_pb.UpdateOrgIDPJWTConfigResponse, error) {
config, err := s.command.ChangeIDPJWTConfig(ctx, updateJWTConfigToDomain(req), authz.GetCtxData(ctx).OrgID)
if err != nil {
return nil, err
}
return &mgmt_pb.UpdateOrgIDPJWTConfigResponse{
Details: object_pb.ChangeToDetailsPb(
config.Sequence,
config.ChangeDate,
config.ResourceOwner,
),
}, nil
}

View File

@@ -12,10 +12,11 @@ import (
func addOIDCIDPRequestToDomain(req *mgmt_pb.AddOrgOIDCIDPRequest) *domain.IDPConfig {
return &domain.IDPConfig{
Name: req.Name,
OIDCConfig: addOIDCIDPRequestToDomainOIDCIDPConfig(req),
StylingType: idp_grpc.IDPStylingTypeToDomain(req.StylingType),
Type: domain.IDPConfigTypeOIDC,
Name: req.Name,
OIDCConfig: addOIDCIDPRequestToDomainOIDCIDPConfig(req),
StylingType: idp_grpc.IDPStylingTypeToDomain(req.StylingType),
Type: domain.IDPConfigTypeOIDC,
AutoRegister: req.AutoRegister,
}
}
@@ -30,6 +31,25 @@ func addOIDCIDPRequestToDomainOIDCIDPConfig(req *mgmt_pb.AddOrgOIDCIDPRequest) *
}
}
func addJWTIDPRequestToDomain(req *mgmt_pb.AddOrgJWTIDPRequest) *domain.IDPConfig {
return &domain.IDPConfig{
Name: req.Name,
JWTConfig: addJWTIDPRequestToDomainJWTIDPConfig(req),
StylingType: idp_grpc.IDPStylingTypeToDomain(req.StylingType),
Type: domain.IDPConfigTypeJWT,
AutoRegister: req.AutoRegister,
}
}
func addJWTIDPRequestToDomainJWTIDPConfig(req *mgmt_pb.AddOrgJWTIDPRequest) *domain.JWTIDPConfig {
return &domain.JWTIDPConfig{
JWTEndpoint: req.JwtEndpoint,
Issuer: req.Issuer,
KeysEndpoint: req.KeysEndpoint,
HeaderName: req.HeaderName,
}
}
func updateIDPToDomain(req *mgmt_pb.UpdateOrgIDPRequest) *domain.IDPConfig {
return &domain.IDPConfig{
IDPConfigID: req.IdpId,
@@ -51,6 +71,16 @@ func updateOIDCConfigToDomain(req *mgmt_pb.UpdateOrgIDPOIDCConfigRequest) *domai
}
}
func updateJWTConfigToDomain(req *mgmt_pb.UpdateOrgIDPJWTConfigRequest) *domain.JWTIDPConfig {
return &domain.JWTIDPConfig{
IDPConfigID: req.IdpId,
JWTEndpoint: req.JwtEndpoint,
Issuer: req.Issuer,
KeysEndpoint: req.KeysEndpoint,
HeaderName: req.HeaderName,
}
}
func listIDPsToModel(req *mgmt_pb.ListOrgIDPsRequest) *iam_model.IDPConfigSearchRequest {
offset, limit, asc := object.ListQueryToModel(req.Query)
return &iam_model.IDPConfigSearchRequest{

View File

@@ -46,7 +46,7 @@ func Test_addOIDCIDPRequestToDomain(t *testing.T) {
"OIDCConfig.AuthorizationEndpoint",
"OIDCConfig.TokenEndpoint",
"Type", //TODO: default (0) is oidc
"AutoRegister",
"JWTConfig",
)
})
}
@@ -114,6 +114,7 @@ func Test_updateIDPToDomain(t *testing.T) {
test.AssertFieldsMapped(t, got,
"ObjectRoot",
"OIDCConfig",
"JWTConfig",
"State",
"Type", //TODO: type should not be changeable
)