forked from spiffe/spire
/
trustdomain.go
136 lines (117 loc) · 4.5 KB
/
trustdomain.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package api
import (
"errors"
"fmt"
"net/url"
"github.com/accuknox/go-spiffe/v2/spiffeid"
"github.com/accuknox/spire/pkg/common/protoutil"
"github.com/accuknox/spire/pkg/server/datastore"
"github.com/accuknox/spire/proto/spire/common"
"github.com/spiffe/spire-api-sdk/proto/spire/api/types"
)
// ProtoToFederationRelationship convert and validate proto to datastore federated relationship
func ProtoToFederationRelationship(f *types.FederationRelationship) (*datastore.FederationRelationship, error) {
return ProtoToFederationRelationshipWithMask(f, nil)
}
// ProtoToFederationRelationshipWithMask convert and validate proto to datastore federated relationship, and apply mask
func ProtoToFederationRelationshipWithMask(f *types.FederationRelationship, mask *types.FederationRelationshipMask) (*datastore.FederationRelationship, error) {
if f == nil {
return nil, errors.New("missing federation relationship")
}
if mask == nil {
mask = protoutil.AllTrueFederationRelationshipMask
}
trustDomain, err := spiffeid.TrustDomainFromString(f.TrustDomain)
if err != nil {
return nil, fmt.Errorf("failed to parse trust domain: %w", err)
}
var bundleEndpointURL *url.URL
if mask.BundleEndpointUrl {
bundleEndpointURL, err = url.Parse(f.BundleEndpointUrl)
switch {
case err != nil:
return nil, fmt.Errorf("failed to parse bundle endpoint URL: %w", err)
case bundleEndpointURL.Scheme != "https":
return nil, errors.New("bundle endpoint URL must use the https scheme")
case bundleEndpointURL.Host == "":
return nil, errors.New("bundle endpoint URL must specify the host")
case bundleEndpointURL.User != nil:
return nil, errors.New("bundle endpoint URL must not contain user info")
}
}
resp := &datastore.FederationRelationship{
TrustDomain: trustDomain,
BundleEndpointURL: bundleEndpointURL,
}
if mask.BundleEndpointProfile {
switch profile := f.BundleEndpointProfile.(type) {
case *types.FederationRelationship_HttpsSpiffe:
if profile.HttpsSpiffe == nil {
return nil, errors.New("bundle endpoint profile does not contain \"HttpsSpiffe\"")
}
spiffeID, err := spiffeid.FromString(profile.HttpsSpiffe.EndpointSpiffeId)
if err != nil {
return nil, fmt.Errorf("failed to parse endpoint SPIFFE ID: %w", err)
}
resp.BundleEndpointProfile = datastore.BundleEndpointSPIFFE
resp.EndpointSPIFFEID = spiffeID
case *types.FederationRelationship_HttpsWeb:
resp.BundleEndpointProfile = datastore.BundleEndpointWeb
default:
return nil, fmt.Errorf("unsupported bundle endpoint profile type: %T", f.BundleEndpointProfile)
}
}
var trustDomainBundle *common.Bundle
if mask.TrustDomainBundle && f.TrustDomainBundle != nil {
trustDomainBundle, err = ProtoToBundle(f.TrustDomainBundle)
if err != nil {
return nil, fmt.Errorf("failed to parse bundle: %w", err)
}
if trustDomainBundle.TrustDomainId != trustDomain.IDString() {
return nil, fmt.Errorf("trust domain bundle (%q) must match the trust domain of the federation relationship (%q)", f.TrustDomainBundle.TrustDomain, trustDomain)
}
resp.TrustDomainBundle = trustDomainBundle
}
return resp, nil
}
// FederationRelationshipToProto converts datastore federation relationship to types proto
func FederationRelationshipToProto(f *datastore.FederationRelationship, mask *types.FederationRelationshipMask) (*types.FederationRelationship, error) {
if mask == nil {
mask = protoutil.AllTrueFederationRelationshipMask
}
if f.TrustDomain.String() == "" {
return nil, errors.New("trust domain is required")
}
resp := &types.FederationRelationship{
TrustDomain: f.TrustDomain.String(),
}
if mask.BundleEndpointUrl {
if f.BundleEndpointURL == nil {
return nil, errors.New("bundle endpoint URL is required")
}
resp.BundleEndpointUrl = f.BundleEndpointURL.String()
}
if mask.BundleEndpointProfile {
switch f.BundleEndpointProfile {
case datastore.BundleEndpointSPIFFE:
profile := &types.FederationRelationship_HttpsSpiffe{
HttpsSpiffe: &types.HTTPSSPIFFEProfile{
EndpointSpiffeId: f.EndpointSPIFFEID.String(),
},
}
resp.BundleEndpointProfile = profile
case datastore.BundleEndpointWeb:
resp.BundleEndpointProfile = &types.FederationRelationship_HttpsWeb{}
default:
return nil, fmt.Errorf("unsupported BundleEndpointProfile: %q", f.BundleEndpointProfile)
}
}
if mask.TrustDomainBundle && f.TrustDomainBundle != nil {
trustDomainBundle, err := BundleToProto(f.TrustDomainBundle)
if err != nil {
return nil, err
}
resp.TrustDomainBundle = trustDomainBundle
}
return resp, nil
}