mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 00:57:33 +00:00
feat: add domain verification (#560)
* feat: add domain verification * add checks * add and fix tests * fix go.mod * regenerate proto
This commit is contained in:
@@ -65,6 +65,26 @@ func (s *Server) AddMyOrgDomain(ctx context.Context, in *management.AddOrgDomain
|
||||
return orgDomainFromModel(domain), nil
|
||||
}
|
||||
|
||||
func (s *Server) GenerateMyOrgDomainValidation(ctx context.Context, in *management.OrgDomainValidationRequest) (*management.OrgDomainValidationResponse, error) {
|
||||
token, url, err := s.org.GenerateMyOrgDomainValidation(ctx, orgDomainValidationToModel(in))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &management.OrgDomainValidationResponse{
|
||||
Token: token,
|
||||
Url: url,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) ValidateMyOrgDomain(ctx context.Context, in *management.ValidateOrgDomainRequest) (*empty.Empty, error) {
|
||||
err := s.org.ValidateMyOrgDomain(ctx, validateOrgDomainToModel(in))
|
||||
return &empty.Empty{}, err
|
||||
}
|
||||
func (s *Server) SetMyPrimaryOrgDomain(ctx context.Context, in *management.PrimaryOrgDomainRequest) (*empty.Empty, error) {
|
||||
err := s.org.SetMyPrimaryOrgDomain(ctx, primaryOrgDomainToModel(in))
|
||||
return &empty.Empty{}, err
|
||||
}
|
||||
|
||||
func (s *Server) RemoveMyOrgDomain(ctx context.Context, in *management.RemoveOrgDomainRequest) (*empty.Empty, error) {
|
||||
err := s.org.RemoveMyOrgDomain(ctx, in.Domain)
|
||||
return &empty.Empty{}, err
|
||||
|
@@ -68,6 +68,32 @@ func addOrgDomainToModel(domain *management.AddOrgDomainRequest) *org_model.OrgD
|
||||
return &org_model.OrgDomain{Domain: domain.Domain}
|
||||
}
|
||||
|
||||
func orgDomainValidationToModel(domain *management.OrgDomainValidationRequest) *org_model.OrgDomain {
|
||||
return &org_model.OrgDomain{
|
||||
Domain: domain.Domain,
|
||||
ValidationType: orgDomainValidationTypeToModel(domain.Type),
|
||||
}
|
||||
}
|
||||
|
||||
func validateOrgDomainToModel(domain *management.ValidateOrgDomainRequest) *org_model.OrgDomain {
|
||||
return &org_model.OrgDomain{Domain: domain.Domain}
|
||||
}
|
||||
|
||||
func orgDomainValidationTypeToModel(key management.OrgDomainValidationType) org_model.OrgDomainValidationType {
|
||||
switch key {
|
||||
case management.OrgDomainValidationType_ORGDOMAINVALIDATIONTYPE_HTTP:
|
||||
return org_model.OrgDomainValidationTypeHTTP
|
||||
case management.OrgDomainValidationType_ORGDOMAINVALIDATIONTYPE_DNS:
|
||||
return org_model.OrgDomainValidationTypeDNS
|
||||
default:
|
||||
return org_model.OrgDomainValidationTypeUnspecified
|
||||
}
|
||||
}
|
||||
|
||||
func primaryOrgDomainToModel(domain *management.PrimaryOrgDomainRequest) *org_model.OrgDomain {
|
||||
return &org_model.OrgDomain{Domain: domain.Domain}
|
||||
}
|
||||
|
||||
func orgDomainFromModel(domain *org_model.OrgDomain) *management.OrgDomain {
|
||||
creationDate, err := ptypes.TimestampProto(domain.CreationDate)
|
||||
logging.Log("GRPC-u8Ksj").OnError(err).Debug("unable to get timestamp from time")
|
||||
|
83
internal/api/http/domain_check.go
Normal file
83
internal/api/http/domain_check.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
)
|
||||
|
||||
type CheckType int
|
||||
|
||||
const (
|
||||
CheckTypeHTTP CheckType = iota
|
||||
CheckTypeDNS
|
||||
|
||||
HTTPPattern = "https://%s/.well-known/zitadel-challenge/%s"
|
||||
DNSPattern = "_zitadel-challenge.%s"
|
||||
)
|
||||
|
||||
func ValidateDomain(domain, token, verifier string, checkType CheckType) error {
|
||||
switch checkType {
|
||||
case CheckTypeHTTP:
|
||||
return ValidateDomainHTTP(domain, token, verifier)
|
||||
case CheckTypeDNS:
|
||||
return ValidateDomainDNS(domain, verifier)
|
||||
default:
|
||||
return errors.ThrowInvalidArgument(nil, "HTTP-Iqd11", "Errors.Internal")
|
||||
}
|
||||
}
|
||||
|
||||
func ValidateDomainHTTP(domain, token, verifier string) error {
|
||||
resp, err := http.Get(tokenUrlHTTP(domain, token))
|
||||
if err != nil {
|
||||
return errors.ThrowInternal(err, "HTTP-BH42h", "Errors.Internal")
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
return errors.ThrowInternal(err, "HTTP-G2zsw", "Errors.Internal")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return errors.ThrowInternal(err, "HTTP-HB432", "Errors.Internal")
|
||||
}
|
||||
if string(body) == verifier {
|
||||
return nil
|
||||
}
|
||||
return errors.ThrowInvalidArgument(err, "HTTP-GH422", "Errors.Internal")
|
||||
}
|
||||
|
||||
func ValidateDomainDNS(domain, verifier string) error {
|
||||
txtRecords, err := net.LookupTXT(tokenUrlDNS(domain))
|
||||
if err != nil {
|
||||
return errors.ThrowInternal(err, "HTTP-Hwsw2", "Errors.Internal")
|
||||
}
|
||||
|
||||
for _, record := range txtRecords {
|
||||
if record == verifier {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return errors.ThrowInvalidArgument(err, "HTTP-G241f", "Errors.Internal")
|
||||
}
|
||||
|
||||
func TokenUrl(domain, token string, checkType CheckType) (string, error) {
|
||||
switch checkType {
|
||||
case CheckTypeHTTP:
|
||||
return tokenUrlHTTP(domain, token), nil
|
||||
case CheckTypeDNS:
|
||||
return tokenUrlDNS(domain), nil
|
||||
default:
|
||||
return "", errors.ThrowInvalidArgument(nil, "HTTP-Iqd11", "")
|
||||
}
|
||||
}
|
||||
|
||||
func tokenUrlHTTP(domain, token string) string {
|
||||
return fmt.Sprintf(HTTPPattern, domain, token)
|
||||
}
|
||||
|
||||
func tokenUrlDNS(domain string) string {
|
||||
return fmt.Sprintf(DNSPattern, domain)
|
||||
}
|
Reference in New Issue
Block a user