feat: add gitlab provider templates (#5405)

* feat(api): add google provider template

* refactor reduce functions

* handle removed event

* linting

* fix projection

* feat(api): add generic oauth provider template

* feat(api): add github provider templates

* feat(api): add github provider templates

* fixes

* proto comment

* fix filtering

* requested changes

* feat(api): add generic oauth provider template

* remove wrongly committed message

* increase budget for angular build

* fix linting

* fixes

* fix merge

* fix merge

* fix projection

* fix merge

* updates from previous PRs

* enable github providers in login

* fix merge

* fix test and add github styling in login

* cleanup

* feat(api): add gitlab provider templates

* fix: merge

* fix display of providers in login

* implement gitlab in login and make prompt `select_account` optional since gitlab can't handle it

* fix merge

* fix merge and add tests for command side

* requested changes

* requested changes

* Update internal/query/idp_template.go

Co-authored-by: Silvan <silvan.reusser@gmail.com>

* fix merge

* requested changes

---------

Co-authored-by: Silvan <silvan.reusser@gmail.com>
This commit is contained in:
Livio Spring
2023-03-13 17:34:29 +01:00
committed by GitHub
parent f55877eb70
commit c0843e6b4c
41 changed files with 5617 additions and 227 deletions

View File

@@ -283,6 +283,48 @@ func (s *Server) UpdateGitHubEnterpriseServerProvider(ctx context.Context, req *
}, nil
}
func (s *Server) AddGitLabProvider(ctx context.Context, req *admin_pb.AddGitLabProviderRequest) (*admin_pb.AddGitLabProviderResponse, error) {
id, details, err := s.command.AddInstanceGitLabProvider(ctx, addGitLabProviderToCommand(req))
if err != nil {
return nil, err
}
return &admin_pb.AddGitLabProviderResponse{
Id: id,
Details: object_pb.DomainToAddDetailsPb(details),
}, nil
}
func (s *Server) UpdateGitLabProvider(ctx context.Context, req *admin_pb.UpdateGitLabProviderRequest) (*admin_pb.UpdateGitLabProviderResponse, error) {
details, err := s.command.UpdateInstanceGitLabProvider(ctx, req.Id, updateGitLabProviderToCommand(req))
if err != nil {
return nil, err
}
return &admin_pb.UpdateGitLabProviderResponse{
Details: object_pb.DomainToChangeDetailsPb(details),
}, nil
}
func (s *Server) AddGitLabSelfHostedProvider(ctx context.Context, req *admin_pb.AddGitLabSelfHostedProviderRequest) (*admin_pb.AddGitLabSelfHostedProviderResponse, error) {
id, details, err := s.command.AddInstanceGitLabSelfHostedProvider(ctx, addGitLabSelfHostedProviderToCommand(req))
if err != nil {
return nil, err
}
return &admin_pb.AddGitLabSelfHostedProviderResponse{
Id: id,
Details: object_pb.DomainToAddDetailsPb(details),
}, nil
}
func (s *Server) UpdateGitLabSelfHostedProvider(ctx context.Context, req *admin_pb.UpdateGitLabSelfHostedProviderRequest) (*admin_pb.UpdateGitLabSelfHostedProviderResponse, error) {
details, err := s.command.UpdateInstanceGitLabSelfHostedProvider(ctx, req.Id, updateGitLabSelfHostedProviderToCommand(req))
if err != nil {
return nil, err
}
return &admin_pb.UpdateGitLabSelfHostedProviderResponse{
Details: object_pb.DomainToChangeDetailsPb(details),
}, nil
}
func (s *Server) AddGoogleProvider(ctx context.Context, req *admin_pb.AddGoogleProviderRequest) (*admin_pb.AddGoogleProviderResponse, error) {
id, details, err := s.command.AddInstanceGoogleProvider(ctx, addGoogleProviderToCommand(req))
if err != nil {

View File

@@ -319,6 +319,48 @@ func updateGitHubEnterpriseProviderToCommand(req *admin_pb.UpdateGitHubEnterpris
}
}
func addGitLabProviderToCommand(req *admin_pb.AddGitLabProviderRequest) command.GitLabProvider {
return command.GitLabProvider{
Name: req.Name,
ClientID: req.ClientId,
ClientSecret: req.ClientSecret,
Scopes: req.Scopes,
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
}
}
func updateGitLabProviderToCommand(req *admin_pb.UpdateGitLabProviderRequest) command.GitLabProvider {
return command.GitLabProvider{
Name: req.Name,
ClientID: req.ClientId,
ClientSecret: req.ClientSecret,
Scopes: req.Scopes,
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
}
}
func addGitLabSelfHostedProviderToCommand(req *admin_pb.AddGitLabSelfHostedProviderRequest) command.GitLabSelfHostedProvider {
return command.GitLabSelfHostedProvider{
Name: req.Name,
Issuer: req.Issuer,
ClientID: req.ClientId,
ClientSecret: req.ClientSecret,
Scopes: req.Scopes,
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
}
}
func updateGitLabSelfHostedProviderToCommand(req *admin_pb.UpdateGitLabSelfHostedProviderRequest) command.GitLabSelfHostedProvider {
return command.GitLabSelfHostedProvider{
Name: req.Name,
Issuer: req.Issuer,
ClientID: req.ClientId,
ClientSecret: req.ClientSecret,
Scopes: req.Scopes,
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
}
}
func addGoogleProviderToCommand(req *admin_pb.AddGoogleProviderRequest) command.GoogleProvider {
return command.GoogleProvider{
Name: req.Name,

View File

@@ -420,6 +420,14 @@ func configToPb(config *query.IDPTemplate) *idp_pb.ProviderConfig {
githubEnterpriseConfigToPb(providerConfig, config.GitHubEnterpriseIDPTemplate)
return providerConfig
}
if config.GitLabIDPTemplate != nil {
gitlabConfigToPb(providerConfig, config.GitLabIDPTemplate)
return providerConfig
}
if config.GitLabSelfHostedIDPTemplate != nil {
gitlabSelfHostedConfigToPb(providerConfig, config.GitLabSelfHostedIDPTemplate)
return providerConfig
}
if config.GoogleIDPTemplate != nil {
googleConfigToPb(providerConfig, config.GoogleIDPTemplate)
return providerConfig
@@ -486,6 +494,25 @@ func githubEnterpriseConfigToPb(providerConfig *idp_pb.ProviderConfig, template
}
}
func gitlabConfigToPb(providerConfig *idp_pb.ProviderConfig, template *query.GitLabIDPTemplate) {
providerConfig.Config = &idp_pb.ProviderConfig_Gitlab{
Gitlab: &idp_pb.GitLabConfig{
ClientId: template.ClientID,
Scopes: template.Scopes,
},
}
}
func gitlabSelfHostedConfigToPb(providerConfig *idp_pb.ProviderConfig, template *query.GitLabSelfHostedIDPTemplate) {
providerConfig.Config = &idp_pb.ProviderConfig_GitlabSelfHosted{
GitlabSelfHosted: &idp_pb.GitLabSelfHostedConfig{
ClientId: template.ClientID,
Issuer: template.Issuer,
Scopes: template.Scopes,
},
}
}
func googleConfigToPb(providerConfig *idp_pb.ProviderConfig, template *query.GoogleIDPTemplate) {
providerConfig.Config = &idp_pb.ProviderConfig_Google{
Google: &idp_pb.GoogleConfig{

View File

@@ -275,6 +275,48 @@ func (s *Server) UpdateGitHubEnterpriseServerProvider(ctx context.Context, req *
}, nil
}
func (s *Server) AddGitLabProvider(ctx context.Context, req *mgmt_pb.AddGitLabProviderRequest) (*mgmt_pb.AddGitLabProviderResponse, error) {
id, details, err := s.command.AddOrgGitLabProvider(ctx, authz.GetCtxData(ctx).OrgID, addGitLabProviderToCommand(req))
if err != nil {
return nil, err
}
return &mgmt_pb.AddGitLabProviderResponse{
Id: id,
Details: object_pb.DomainToAddDetailsPb(details),
}, nil
}
func (s *Server) UpdateGitLabProvider(ctx context.Context, req *mgmt_pb.UpdateGitLabProviderRequest) (*mgmt_pb.UpdateGitLabProviderResponse, error) {
details, err := s.command.UpdateOrgGitLabProvider(ctx, authz.GetCtxData(ctx).OrgID, req.Id, updateGitLabProviderToCommand(req))
if err != nil {
return nil, err
}
return &mgmt_pb.UpdateGitLabProviderResponse{
Details: object_pb.DomainToChangeDetailsPb(details),
}, nil
}
func (s *Server) AddGitLabSelfHostedProvider(ctx context.Context, req *mgmt_pb.AddGitLabSelfHostedProviderRequest) (*mgmt_pb.AddGitLabSelfHostedProviderResponse, error) {
id, details, err := s.command.AddOrgGitLabSelfHostedProvider(ctx, authz.GetCtxData(ctx).OrgID, addGitLabSelfHostedProviderToCommand(req))
if err != nil {
return nil, err
}
return &mgmt_pb.AddGitLabSelfHostedProviderResponse{
Id: id,
Details: object_pb.DomainToAddDetailsPb(details),
}, nil
}
func (s *Server) UpdateGitLabSelfHostedProvider(ctx context.Context, req *mgmt_pb.UpdateGitLabSelfHostedProviderRequest) (*mgmt_pb.UpdateGitLabSelfHostedProviderResponse, error) {
details, err := s.command.UpdateOrgGitLabSelfHostedProvider(ctx, authz.GetCtxData(ctx).OrgID, req.Id, updateGitLabSelfHostedProviderToCommand(req))
if err != nil {
return nil, err
}
return &mgmt_pb.UpdateGitLabSelfHostedProviderResponse{
Details: object_pb.DomainToChangeDetailsPb(details),
}, nil
}
func (s *Server) AddGoogleProvider(ctx context.Context, req *mgmt_pb.AddGoogleProviderRequest) (*mgmt_pb.AddGoogleProviderResponse, error) {
id, details, err := s.command.AddOrgGoogleProvider(ctx, authz.GetCtxData(ctx).OrgID, addGoogleProviderToCommand(req))
if err != nil {

View File

@@ -336,6 +336,48 @@ func updateGitHubEnterpriseProviderToCommand(req *mgmt_pb.UpdateGitHubEnterprise
}
}
func addGitLabProviderToCommand(req *mgmt_pb.AddGitLabProviderRequest) command.GitLabProvider {
return command.GitLabProvider{
Name: req.Name,
ClientID: req.ClientId,
ClientSecret: req.ClientSecret,
Scopes: req.Scopes,
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
}
}
func updateGitLabProviderToCommand(req *mgmt_pb.UpdateGitLabProviderRequest) command.GitLabProvider {
return command.GitLabProvider{
Name: req.Name,
ClientID: req.ClientId,
ClientSecret: req.ClientSecret,
Scopes: req.Scopes,
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
}
}
func addGitLabSelfHostedProviderToCommand(req *mgmt_pb.AddGitLabSelfHostedProviderRequest) command.GitLabSelfHostedProvider {
return command.GitLabSelfHostedProvider{
Name: req.Name,
Issuer: req.Issuer,
ClientID: req.ClientId,
ClientSecret: req.ClientSecret,
Scopes: req.Scopes,
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
}
}
func updateGitLabSelfHostedProviderToCommand(req *mgmt_pb.UpdateGitLabSelfHostedProviderRequest) command.GitLabSelfHostedProvider {
return command.GitLabSelfHostedProvider{
Name: req.Name,
Issuer: req.Issuer,
ClientID: req.ClientId,
ClientSecret: req.ClientSecret,
Scopes: req.Scopes,
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
}
}
func addGoogleProviderToCommand(req *mgmt_pb.AddGoogleProviderRequest) command.GoogleProvider {
return command.GoogleProvider{
Name: req.Name,

View File

@@ -19,6 +19,7 @@ import (
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
"github.com/zitadel/zitadel/internal/idp"
"github.com/zitadel/zitadel/internal/idp/providers/github"
"github.com/zitadel/zitadel/internal/idp/providers/gitlab"
"github.com/zitadel/zitadel/internal/idp/providers/google"
"github.com/zitadel/zitadel/internal/idp/providers/jwt"
"github.com/zitadel/zitadel/internal/idp/providers/oauth"
@@ -146,12 +147,14 @@ func (l *Login) handleIDP(w http.ResponseWriter, r *http.Request, authReq *domai
provider, err = l.githubProvider(r.Context(), identityProvider)
case domain.IDPTypeGitHubEnterprise:
provider, err = l.githubEnterpriseProvider(r.Context(), identityProvider)
case domain.IDPTypeGitLab:
provider, err = l.gitlabProvider(r.Context(), identityProvider)
case domain.IDPTypeGitLabSelfHosted:
provider, err = l.gitlabSelfHostedProvider(r.Context(), identityProvider)
case domain.IDPTypeGoogle:
provider, err = l.googleProvider(r.Context(), identityProvider)
case domain.IDPTypeLDAP,
domain.IDPTypeAzureAD,
domain.IDPTypeGitLab,
domain.IDPTypeGitLabSelfHosted,
domain.IDPTypeUnspecified:
fallthrough
default:
@@ -221,6 +224,20 @@ func (l *Login) handleExternalLoginCallback(w http.ResponseWriter, r *http.Reque
return
}
session = &oauth.Session{Provider: provider.(*github.Provider).Provider, Code: data.Code}
case domain.IDPTypeGitLab:
provider, err = l.gitlabProvider(r.Context(), identityProvider)
if err != nil {
l.externalAuthFailed(w, r, authReq, nil, nil, err)
return
}
session = &openid.Session{Provider: provider.(*gitlab.Provider).Provider, Code: data.Code}
case domain.IDPTypeGitLabSelfHosted:
provider, err = l.gitlabSelfHostedProvider(r.Context(), identityProvider)
if err != nil {
l.externalAuthFailed(w, r, authReq, nil, nil, err)
return
}
session = &openid.Session{Provider: provider.(*gitlab.Provider).Provider, Code: data.Code}
case domain.IDPTypeGoogle:
provider, err = l.googleProvider(r.Context(), identityProvider)
if err != nil {
@@ -231,8 +248,6 @@ func (l *Login) handleExternalLoginCallback(w http.ResponseWriter, r *http.Reque
case domain.IDPTypeJWT,
domain.IDPTypeLDAP,
domain.IDPTypeAzureAD,
domain.IDPTypeGitLab,
domain.IDPTypeGitLabSelfHosted,
domain.IDPTypeUnspecified:
fallthrough
default:
@@ -609,6 +624,7 @@ func (l *Login) oidcProvider(ctx context.Context, identityProvider *query.IDPTem
l.baseURL(ctx)+EndpointExternalLoginCallback,
identityProvider.OIDCIDPTemplate.Scopes,
openid.DefaultMapper,
openid.WithSelectAccount(),
)
}
@@ -678,6 +694,34 @@ func (l *Login) githubEnterpriseProvider(ctx context.Context, identityProvider *
)
}
func (l *Login) gitlabProvider(ctx context.Context, identityProvider *query.IDPTemplate) (*gitlab.Provider, error) {
secret, err := crypto.DecryptString(identityProvider.GitLabIDPTemplate.ClientSecret, l.idpConfigAlg)
if err != nil {
return nil, err
}
return gitlab.New(
identityProvider.GitLabIDPTemplate.ClientID,
secret,
l.baseURL(ctx)+EndpointExternalLoginCallback,
identityProvider.GitLabIDPTemplate.Scopes,
)
}
func (l *Login) gitlabSelfHostedProvider(ctx context.Context, identityProvider *query.IDPTemplate) (*gitlab.Provider, error) {
secret, err := crypto.DecryptString(identityProvider.GitLabSelfHostedIDPTemplate.ClientSecret, l.idpConfigAlg)
if err != nil {
return nil, err
}
return gitlab.NewCustomIssuer(
identityProvider.Name,
identityProvider.GitLabSelfHostedIDPTemplate.Issuer,
identityProvider.GitLabSelfHostedIDPTemplate.ClientID,
secret,
l.baseURL(ctx)+EndpointExternalLoginCallback,
identityProvider.GitLabSelfHostedIDPTemplate.Scopes,
)
}
func (l *Login) appendUserGrants(ctx context.Context, userGrants []*domain.UserGrant, resourceOwner string) error {
if len(userGrants) == 0 {
return nil

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -4,6 +4,7 @@ $lgn-idp-provider-name-line-height: 36px;
$lgn-idp-border-radius: .5rem;
$googlelogosource: '../../../images/idp/google';
$githublogosource: '../../../images/idp/github';
$gitlablogosource: '../../../images/idp/gitlab';
@mixin lgn-idp-base {
display: block;
@@ -52,4 +53,16 @@ $githublogosource: '../../../images/idp/github';
border-radius: 5px;
}
}
&.gitlab {
span.logo {
height: 46px;
width: 46px;
background-image: url($gitlablogosource + '.png');
background-size: 100%;
background-position: center;
background-repeat: no-repeat;
border-radius: 5px;
}
}
}

View File

@@ -26,6 +26,11 @@
color: var(--zitadel-color-github-text);
background-color: var(--zitadel-color-github-background);
}
&.gitlab {
color: var(--zitadel-color-gitlab-text);
background-color: var(--zitadel-color-gitlab-background);
}
}
.lgn-idp-providers {

View File

@@ -115,6 +115,8 @@
--zitadel-color-google-background: #ffffff;
--zitadel-color-github-text: #8b8d8d;
--zitadel-color-github-background: #ffffff;
--zitadel-color-gitlab-text: #8b8d8d;
--zitadel-color-gitlab-background: #ffffff;
--zitadel-color-qr: var(--zitadel-color-black);
--zitadel-color-qr-background: var(--zitadel-color-white);
@@ -218,4 +220,6 @@
--zitadel-color-google-background: #ffffff;
--zitadel-color-github-text: #8b8d8d;
--zitadel-color-github-background: #ffffff;
--zitadel-color-gitlab-text: #8b8d8d;
--zitadel-color-gitlab-background: #ffffff;
}

View File

@@ -100,6 +100,8 @@
--zitadel-color-google-background: #ffffff;
--zitadel-color-github-text: #8b8d8d;
--zitadel-color-github-background: #ffffff;
--zitadel-color-gitlab-text: #8b8d8d;
--zitadel-color-gitlab-background: #ffffff;
--zitadel-color-qr: var(--zitadel-color-black);
--zitadel-color-qr-background: var(--zitadel-color-white);
}
@@ -188,6 +190,8 @@
--zitadel-color-google-background: #ffffff;
--zitadel-color-github-text: #8b8d8d;
--zitadel-color-github-background: #ffffff;
--zitadel-color-gitlab-text: #8b8d8d;
--zitadel-color-gitlab-background: #ffffff;
}
body {
@@ -572,6 +576,15 @@ a.sub-formfield-link {
background-repeat: no-repeat;
border-radius: 5px;
}
.lgn-idp.gitlab span.logo {
height: 46px;
width: 46px;
background-image: url("../../../images/idp/gitlab.png");
background-size: 100%;
background-position: center;
background-repeat: no-repeat;
border-radius: 5px;
}
.lgn-error {
display: flex;
@@ -1556,6 +1569,15 @@ a.sub-formfield-link {
background-repeat: no-repeat;
border-radius: 5px;
}
.lgn-idp.gitlab span.logo {
height: 46px;
width: 46px;
background-image: url("../../../images/idp/gitlab.png");
background-size: 100%;
background-position: center;
background-repeat: no-repeat;
border-radius: 5px;
}
.lgn-error {
display: flex;
@@ -3073,6 +3095,10 @@ ul li i.lgn-valid {
color: var(--zitadel-color-github-text);
background-color: var(--zitadel-color-github-background);
}
.lgn-idp.gitlab {
color: var(--zitadel-color-gitlab-text);
background-color: var(--zitadel-color-gitlab-background);
}
.lgn-idp-providers .lgn-idp-desc {
color: var(--zitadel-color-label);

File diff suppressed because one or more lines are too long

View File

@@ -49,7 +49,7 @@
<a href="{{ externalIDPAuthURL $reqid $provider.IDPConfigID}}"
class="lgn-idp {{idpProviderClass $provider.IDPType}}">
<span class="logo"></span>
<span class="provider-name">{{$provider.Name}}</span>
<span class="provider-name">{{$provider.DisplayName}}</span>
</a>
{{end}}
</div>

View File

@@ -29,7 +29,7 @@
<a href="{{ externalIDPRegisterURL $reqid $provider.IDPConfigID}}"
class="lgn-idp {{idpProviderClass $provider.IDPType}}">
<span class="logo"></span>
<span class="provider-name">{{$provider.Name}}</span>
<span class="provider-name">{{$provider.DisplayName}}</span>
</a>
{{end}}
{{end}}