mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-03 04:52:11 +00:00
feat: add azure provider templates (#5441)
Adds possibility to manage and use Microsoft Azure template based providers
This commit is contained in:
@@ -241,6 +241,27 @@ func (s *Server) UpdateJWTProvider(ctx context.Context, req *admin_pb.UpdateJWTP
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) AddAzureADProvider(ctx context.Context, req *admin_pb.AddAzureADProviderRequest) (*admin_pb.AddAzureADProviderResponse, error) {
|
||||
id, details, err := s.command.AddInstanceAzureADProvider(ctx, addAzureADProviderToCommand(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.AddAzureADProviderResponse{
|
||||
Id: id,
|
||||
Details: object_pb.DomainToAddDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) UpdateAzureADProvider(ctx context.Context, req *admin_pb.UpdateAzureADProviderRequest) (*admin_pb.UpdateAzureADProviderResponse, error) {
|
||||
details, err := s.command.UpdateInstanceAzureADProvider(ctx, req.Id, updateAzureADProviderToCommand(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.UpdateAzureADProviderResponse{
|
||||
Details: object_pb.DomainToChangeDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) AddGitHubProvider(ctx context.Context, req *admin_pb.AddGitHubProviderRequest) (*admin_pb.AddGitHubProviderResponse, error) {
|
||||
id, details, err := s.command.AddInstanceGitHubProvider(ctx, addGitHubProviderToCommand(req))
|
||||
if err != nil {
|
||||
|
||||
@@ -273,6 +273,30 @@ func updateJWTProviderToCommand(req *admin_pb.UpdateJWTProviderRequest) command.
|
||||
}
|
||||
}
|
||||
|
||||
func addAzureADProviderToCommand(req *admin_pb.AddAzureADProviderRequest) command.AzureADProvider {
|
||||
return command.AzureADProvider{
|
||||
Name: req.Name,
|
||||
ClientID: req.ClientId,
|
||||
ClientSecret: req.ClientSecret,
|
||||
Scopes: req.Scopes,
|
||||
Tenant: idp_grpc.AzureADTenantToCommand(req.Tenant),
|
||||
EmailVerified: req.EmailVerified,
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
}
|
||||
}
|
||||
|
||||
func updateAzureADProviderToCommand(req *admin_pb.UpdateAzureADProviderRequest) command.AzureADProvider {
|
||||
return command.AzureADProvider{
|
||||
Name: req.Name,
|
||||
ClientID: req.ClientId,
|
||||
ClientSecret: req.ClientSecret,
|
||||
Scopes: req.Scopes,
|
||||
Tenant: idp_grpc.AzureADTenantToCommand(req.Tenant),
|
||||
EmailVerified: req.EmailVerified,
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
}
|
||||
}
|
||||
|
||||
func addGitHubProviderToCommand(req *admin_pb.AddGitHubProviderRequest) command.GitHubProvider {
|
||||
return command.GitHubProvider{
|
||||
Name: req.Name,
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
obj_grpc "github.com/zitadel/zitadel/internal/api/grpc/object"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
iam_model "github.com/zitadel/zitadel/internal/iam/model"
|
||||
"github.com/zitadel/zitadel/internal/idp/providers/azuread"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
"github.com/zitadel/zitadel/internal/repository/idp"
|
||||
idp_pb "github.com/zitadel/zitadel/pkg/grpc/idp"
|
||||
@@ -329,6 +330,33 @@ func LDAPAttributesToCommand(attributes *idp_pb.LDAPAttributes) idp.LDAPAttribut
|
||||
}
|
||||
}
|
||||
|
||||
func AzureADTenantToCommand(tenant *idp_pb.AzureADTenant) string {
|
||||
if tenant == nil {
|
||||
return string(azuread.CommonTenant)
|
||||
}
|
||||
switch t := tenant.Type.(type) {
|
||||
case *idp_pb.AzureADTenant_TenantType:
|
||||
return string(azureADTenantTypeToCommand(t.TenantType))
|
||||
case *idp_pb.AzureADTenant_TenantId:
|
||||
return t.TenantId
|
||||
default:
|
||||
return string(azuread.CommonTenant)
|
||||
}
|
||||
}
|
||||
|
||||
func azureADTenantTypeToCommand(tenantType idp_pb.AzureADTenantType) azuread.TenantType {
|
||||
switch tenantType {
|
||||
case idp_pb.AzureADTenantType_AZURE_AD_TENANT_TYPE_COMMON:
|
||||
return azuread.CommonTenant
|
||||
case idp_pb.AzureADTenantType_AZURE_AD_TENANT_TYPE_ORGANISATIONS:
|
||||
return azuread.OrganizationsTenant
|
||||
case idp_pb.AzureADTenantType_AZURE_AD_TENANT_TYPE_CONSUMERS:
|
||||
return azuread.ConsumersTenant
|
||||
default:
|
||||
return azuread.CommonTenant
|
||||
}
|
||||
}
|
||||
|
||||
func ProvidersToPb(providers []*query.IDPTemplate) []*idp_pb.Provider {
|
||||
list := make([]*idp_pb.Provider, len(providers))
|
||||
for i, provider := range providers {
|
||||
@@ -412,6 +440,10 @@ func configToPb(config *query.IDPTemplate) *idp_pb.ProviderConfig {
|
||||
jwtConfigToPb(providerConfig, config.JWTIDPTemplate)
|
||||
return providerConfig
|
||||
}
|
||||
if config.AzureADIDPTemplate != nil {
|
||||
azureConfigToPb(providerConfig, config.AzureADIDPTemplate)
|
||||
return providerConfig
|
||||
}
|
||||
if config.GitHubIDPTemplate != nil {
|
||||
githubConfigToPb(providerConfig, config.GitHubIDPTemplate)
|
||||
return providerConfig
|
||||
@@ -473,6 +505,32 @@ func jwtConfigToPb(providerConfig *idp_pb.ProviderConfig, template *query.JWTIDP
|
||||
}
|
||||
}
|
||||
|
||||
func azureConfigToPb(providerConfig *idp_pb.ProviderConfig, template *query.AzureADIDPTemplate) {
|
||||
providerConfig.Config = &idp_pb.ProviderConfig_AzureAd{
|
||||
AzureAd: &idp_pb.AzureADConfig{
|
||||
ClientId: template.ClientID,
|
||||
Tenant: azureTenantToPb(template.Tenant),
|
||||
EmailVerified: template.IsEmailVerified,
|
||||
Scopes: template.Scopes,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func azureTenantToPb(tenant string) *idp_pb.AzureADTenant {
|
||||
var tenantType idp_pb.IsAzureADTenantType
|
||||
switch azuread.TenantType(tenant) {
|
||||
case azuread.CommonTenant:
|
||||
tenantType = &idp_pb.AzureADTenant_TenantType{TenantType: idp_pb.AzureADTenantType_AZURE_AD_TENANT_TYPE_COMMON}
|
||||
case azuread.OrganizationsTenant:
|
||||
tenantType = &idp_pb.AzureADTenant_TenantType{TenantType: idp_pb.AzureADTenantType_AZURE_AD_TENANT_TYPE_ORGANISATIONS}
|
||||
case azuread.ConsumersTenant:
|
||||
tenantType = &idp_pb.AzureADTenant_TenantType{TenantType: idp_pb.AzureADTenantType_AZURE_AD_TENANT_TYPE_CONSUMERS}
|
||||
default:
|
||||
tenantType = &idp_pb.AzureADTenant_TenantId{TenantId: tenant}
|
||||
}
|
||||
return &idp_pb.AzureADTenant{Type: tenantType}
|
||||
}
|
||||
|
||||
func githubConfigToPb(providerConfig *idp_pb.ProviderConfig, template *query.GitHubIDPTemplate) {
|
||||
providerConfig.Config = &idp_pb.ProviderConfig_Github{
|
||||
Github: &idp_pb.GitHubConfig{
|
||||
|
||||
@@ -233,6 +233,27 @@ func (s *Server) UpdateJWTProvider(ctx context.Context, req *mgmt_pb.UpdateJWTPr
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) AddAzureADProvider(ctx context.Context, req *mgmt_pb.AddAzureADProviderRequest) (*mgmt_pb.AddAzureADProviderResponse, error) {
|
||||
id, details, err := s.command.AddOrgAzureADProvider(ctx, authz.GetCtxData(ctx).OrgID, addAzureADProviderToCommand(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.AddAzureADProviderResponse{
|
||||
Id: id,
|
||||
Details: object_pb.DomainToAddDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) UpdateAzureADProvider(ctx context.Context, req *mgmt_pb.UpdateAzureADProviderRequest) (*mgmt_pb.UpdateAzureADProviderResponse, error) {
|
||||
details, err := s.command.UpdateOrgAzureADProvider(ctx, authz.GetCtxData(ctx).OrgID, req.Id, updateAzureADProviderToCommand(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.UpdateAzureADProviderResponse{
|
||||
Details: object_pb.DomainToChangeDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) AddGitHubProvider(ctx context.Context, req *mgmt_pb.AddGitHubProviderRequest) (*mgmt_pb.AddGitHubProviderResponse, error) {
|
||||
id, details, err := s.command.AddOrgGitHubProvider(ctx, authz.GetCtxData(ctx).OrgID, addGitHubProviderToCommand(req))
|
||||
if err != nil {
|
||||
|
||||
@@ -290,6 +290,28 @@ func updateJWTProviderToCommand(req *mgmt_pb.UpdateJWTProviderRequest) command.J
|
||||
}
|
||||
}
|
||||
|
||||
func addAzureADProviderToCommand(req *mgmt_pb.AddAzureADProviderRequest) command.AzureADProvider {
|
||||
return command.AzureADProvider{
|
||||
Name: req.Name,
|
||||
ClientID: req.ClientId,
|
||||
ClientSecret: req.ClientSecret,
|
||||
Tenant: idp_grpc.AzureADTenantToCommand(req.Tenant),
|
||||
EmailVerified: req.EmailVerified,
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
}
|
||||
}
|
||||
|
||||
func updateAzureADProviderToCommand(req *mgmt_pb.UpdateAzureADProviderRequest) command.AzureADProvider {
|
||||
return command.AzureADProvider{
|
||||
Name: req.Name,
|
||||
ClientID: req.ClientId,
|
||||
ClientSecret: req.ClientSecret,
|
||||
Tenant: idp_grpc.AzureADTenantToCommand(req.Tenant),
|
||||
EmailVerified: req.EmailVerified,
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
}
|
||||
}
|
||||
|
||||
func addGitHubProviderToCommand(req *mgmt_pb.AddGitHubProviderRequest) command.GitHubProvider {
|
||||
return command.GitHubProvider{
|
||||
Name: req.Name,
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/zitadel/zitadel/internal/idp"
|
||||
"github.com/zitadel/zitadel/internal/idp/providers/azuread"
|
||||
"github.com/zitadel/zitadel/internal/idp/providers/github"
|
||||
"github.com/zitadel/zitadel/internal/idp/providers/gitlab"
|
||||
"github.com/zitadel/zitadel/internal/idp/providers/google"
|
||||
@@ -144,6 +145,8 @@ func (l *Login) handleIDP(w http.ResponseWriter, r *http.Request, authReq *domai
|
||||
provider, err = l.oidcProvider(r.Context(), identityProvider)
|
||||
case domain.IDPTypeJWT:
|
||||
provider, err = l.jwtProvider(identityProvider)
|
||||
case domain.IDPTypeAzureAD:
|
||||
provider, err = l.azureProvider(r.Context(), identityProvider)
|
||||
case domain.IDPTypeGitHub:
|
||||
provider, err = l.githubProvider(r.Context(), identityProvider)
|
||||
case domain.IDPTypeGitHubEnterprise:
|
||||
@@ -155,7 +158,6 @@ func (l *Login) handleIDP(w http.ResponseWriter, r *http.Request, authReq *domai
|
||||
case domain.IDPTypeGoogle:
|
||||
provider, err = l.googleProvider(r.Context(), identityProvider)
|
||||
case domain.IDPTypeLDAP,
|
||||
domain.IDPTypeAzureAD,
|
||||
domain.IDPTypeUnspecified:
|
||||
fallthrough
|
||||
default:
|
||||
@@ -212,6 +214,13 @@ func (l *Login) handleExternalLoginCallback(w http.ResponseWriter, r *http.Reque
|
||||
return
|
||||
}
|
||||
session = &openid.Session{Provider: provider.(*openid.Provider), Code: data.Code}
|
||||
case domain.IDPTypeAzureAD:
|
||||
provider, err = l.azureProvider(r.Context(), identityProvider)
|
||||
if err != nil {
|
||||
l.externalAuthFailed(w, r, authReq, nil, nil, err)
|
||||
return
|
||||
}
|
||||
session = &oauth.Session{Provider: provider.(*azuread.Provider).Provider, Code: data.Code}
|
||||
case domain.IDPTypeGitHub:
|
||||
provider, err = l.githubProvider(r.Context(), identityProvider)
|
||||
if err != nil {
|
||||
@@ -249,7 +258,6 @@ func (l *Login) handleExternalLoginCallback(w http.ResponseWriter, r *http.Reque
|
||||
session = &openid.Session{Provider: provider.(*google.Provider).Provider, Code: data.Code}
|
||||
case domain.IDPTypeJWT,
|
||||
domain.IDPTypeLDAP,
|
||||
domain.IDPTypeAzureAD,
|
||||
domain.IDPTypeUnspecified:
|
||||
fallthrough
|
||||
default:
|
||||
@@ -666,6 +674,28 @@ func (l *Login) oauthProvider(ctx context.Context, identityProvider *query.IDPTe
|
||||
)
|
||||
}
|
||||
|
||||
func (l *Login) azureProvider(ctx context.Context, identityProvider *query.IDPTemplate) (*azuread.Provider, error) {
|
||||
secret, err := crypto.DecryptString(identityProvider.AzureADIDPTemplate.ClientSecret, l.idpConfigAlg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts := make([]azuread.ProviderOptions, 0, 2)
|
||||
if identityProvider.AzureADIDPTemplate.IsEmailVerified {
|
||||
opts = append(opts, azuread.WithEmailVerified())
|
||||
}
|
||||
if identityProvider.AzureADIDPTemplate.Tenant != "" {
|
||||
opts = append(opts, azuread.WithTenant(azuread.TenantType(identityProvider.AzureADIDPTemplate.Tenant)))
|
||||
}
|
||||
return azuread.New(
|
||||
identityProvider.Name,
|
||||
identityProvider.AzureADIDPTemplate.ClientID,
|
||||
secret,
|
||||
l.baseURL(ctx)+EndpointExternalLoginCallback,
|
||||
identityProvider.AzureADIDPTemplate.Scopes,
|
||||
opts...,
|
||||
)
|
||||
}
|
||||
|
||||
func (l *Login) githubProvider(ctx context.Context, identityProvider *query.IDPTemplate) (*github.Provider, error) {
|
||||
secret, err := crypto.DecryptString(identityProvider.GitHubIDPTemplate.ClientSecret, l.idpConfigAlg)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user