Harden compliance portal auth and TLS
Align console references and OAuth branding with the compliance-page model, and fix certificate cache eviction, portal OAuth handlers, and magic-link edge cases left after the trust-center rename. Signed-off-by: Bryan Frimin <bryan@probo.com>
This commit is contained in:
@@ -580,6 +580,19 @@ func (s AuthService) SendMagicLink(ctx context.Context, req *SendMagicLinkReques
|
||||
return fmt.Errorf("cannot generate magic link token: %w", err)
|
||||
}
|
||||
|
||||
senderName := magicLinkDefaultSenderName
|
||||
|
||||
if req.OAuth2ClientIDRaw != nil && *req.OAuth2ClientIDRaw != "" {
|
||||
branding, err := s.OAuth2ServerService.ClientBranding(ctx, *req.OAuth2ClientIDRaw)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot load oauth2 client branding: %w", err)
|
||||
}
|
||||
|
||||
if branding != nil {
|
||||
senderName = branding.Name
|
||||
}
|
||||
}
|
||||
|
||||
return s.pg.WithTx(
|
||||
ctx,
|
||||
func(ctx context.Context, tx pg.Tx) error {
|
||||
@@ -596,7 +609,6 @@ func (s AuthService) SendMagicLink(ctx context.Context, req *SendMagicLinkReques
|
||||
|
||||
fullName := req.Email.Username()
|
||||
identity := &coredata.Identity{}
|
||||
senderName := magicLinkDefaultSenderName
|
||||
|
||||
if err := identity.LoadByEmail(ctx, tx, req.Email); err == nil {
|
||||
if identity.FullName != "" {
|
||||
@@ -608,17 +620,6 @@ func (s AuthService) SendMagicLink(ctx context.Context, req *SendMagicLinkReques
|
||||
}
|
||||
}
|
||||
|
||||
if req.OAuth2ClientIDRaw != nil && *req.OAuth2ClientIDRaw != "" {
|
||||
branding, err := s.OAuth2ServerService.ClientBranding(ctx, *req.OAuth2ClientIDRaw)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot load oauth2 client branding: %w", err)
|
||||
}
|
||||
|
||||
if branding != nil {
|
||||
senderName = branding.Name
|
||||
}
|
||||
}
|
||||
|
||||
emailPresenterCfg := emails.DefaultPresenterConfig(s.baseURL)
|
||||
|
||||
if req.MagicLinkBaseURL != nil {
|
||||
|
||||
@@ -26,7 +26,6 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
@@ -117,25 +116,6 @@ func NewIDTokenClaims(
|
||||
return claims
|
||||
}
|
||||
|
||||
func ParseIDTokenClaims(raw string) (*IDTokenClaims, error) {
|
||||
parts := strings.Split(raw, ".")
|
||||
if len(parts) != 3 {
|
||||
return nil, fmt.Errorf("cannot parse id token: invalid format")
|
||||
}
|
||||
|
||||
payload, err := base64.RawURLEncoding.DecodeString(parts[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse id token payload: %w", err)
|
||||
}
|
||||
|
||||
var claims IDTokenClaims
|
||||
if err := json.Unmarshal(payload, &claims); err != nil {
|
||||
return nil, fmt.Errorf("cannot decode id token claims: %w", err)
|
||||
}
|
||||
|
||||
return &claims, nil
|
||||
}
|
||||
|
||||
func ParseIDTokenIdentity(
|
||||
raw string,
|
||||
jwks *jose.JWKS,
|
||||
|
||||
@@ -756,28 +756,34 @@ func (s *OrganizationService) CreateOrganization(
|
||||
return fmt.Errorf("cannot insert mailing list: %w", err)
|
||||
}
|
||||
|
||||
defaultDomainHostname := trustCenter.Slug + "." + s.trustCenterBaseDomain
|
||||
// Self-managed installs without a configured base domain don't get
|
||||
// a default managed domain: there is no suffix to mint a
|
||||
// "{slug}." hostname from, so the compliance page stays without
|
||||
// a domain until the organization adds a custom one.
|
||||
if s.trustCenterBaseDomain != "" {
|
||||
defaultDomainHostname := trustCenter.Slug + "." + s.trustCenterBaseDomain
|
||||
|
||||
defaultDomain := coredata.NewCustomDomain(
|
||||
tenantID,
|
||||
organization.ID,
|
||||
defaultDomainHostname,
|
||||
true,
|
||||
)
|
||||
defaultDomain := coredata.NewCustomDomain(
|
||||
tenantID,
|
||||
organization.ID,
|
||||
defaultDomainHostname,
|
||||
true,
|
||||
)
|
||||
|
||||
certificate, err := s.certManager.EnsureCertificate(ctx, tx, scope, defaultDomainHostname)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot ensure certificate for default custom domain: %w", err)
|
||||
certificate, err := s.certManager.EnsureCertificate(ctx, tx, scope, defaultDomainHostname)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot ensure certificate for default custom domain: %w", err)
|
||||
}
|
||||
|
||||
defaultDomain.CertificateID = &certificate.ID
|
||||
|
||||
if err := defaultDomain.Insert(ctx, tx, scope); err != nil {
|
||||
return fmt.Errorf("cannot insert default custom domain: %w", err)
|
||||
}
|
||||
|
||||
trustCenter.DefaultDomainID = &defaultDomain.ID
|
||||
}
|
||||
|
||||
defaultDomain.CertificateID = &certificate.ID
|
||||
|
||||
if err := defaultDomain.Insert(ctx, tx, scope); err != nil {
|
||||
return fmt.Errorf("cannot insert default custom domain: %w", err)
|
||||
}
|
||||
|
||||
trustCenter.DefaultDomainID = &defaultDomain.ID
|
||||
|
||||
if err := trustCenter.Insert(ctx, tx, scope); err != nil {
|
||||
return fmt.Errorf("cannot insert trust center: %w", err)
|
||||
}
|
||||
|
||||
@@ -62,7 +62,6 @@ type (
|
||||
magicLinkTokenValidity time.Duration
|
||||
sessionDuration time.Duration
|
||||
bucket string
|
||||
encryptionKey cipher.EncryptionKey
|
||||
trustCenterBaseDomain string
|
||||
certManager *certmanager.Service
|
||||
certificate *x509.Certificate
|
||||
@@ -150,6 +149,10 @@ func NewService(
|
||||
return nil, fmt.Errorf("oauth2 scope registry is required")
|
||||
}
|
||||
|
||||
if cfg.CertManager == nil {
|
||||
return nil, fmt.Errorf("cert manager is required")
|
||||
}
|
||||
|
||||
svc := &Service{
|
||||
pg: pgClient,
|
||||
fm: fm,
|
||||
@@ -163,7 +166,6 @@ func NewService(
|
||||
magicLinkTokenValidity: cfg.MagicLinkTokenValidity,
|
||||
sessionDuration: cfg.SessionDuration,
|
||||
bucket: cfg.Bucket,
|
||||
encryptionKey: cfg.EncryptionKey,
|
||||
trustCenterBaseDomain: cfg.TrustCenterBaseDomain,
|
||||
certManager: cfg.CertManager,
|
||||
certificate: cfg.Certificate,
|
||||
|
||||
Reference in New Issue
Block a user