1 package adal
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 import (
18 "errors"
19 "fmt"
20 "net/url"
21 )
22
23 const (
24 activeDirectoryEndpointTemplate = "%s/oauth2/%s%s"
25 )
26
27
28
29 type OAuthConfig struct {
30 AuthorityEndpoint url.URL `json:"authorityEndpoint"`
31 AuthorizeEndpoint url.URL `json:"authorizeEndpoint"`
32 TokenEndpoint url.URL `json:"tokenEndpoint"`
33 DeviceCodeEndpoint url.URL `json:"deviceCodeEndpoint"`
34 }
35
36
37 func (oac OAuthConfig) IsZero() bool {
38 return oac == OAuthConfig{}
39 }
40
41 func validateStringParam(param, name string) error {
42 if len(param) == 0 {
43 return fmt.Errorf("parameter '" + name + "' cannot be empty")
44 }
45 return nil
46 }
47
48
49 func NewOAuthConfig(activeDirectoryEndpoint, tenantID string) (*OAuthConfig, error) {
50 apiVer := "1.0"
51 return NewOAuthConfigWithAPIVersion(activeDirectoryEndpoint, tenantID, &apiVer)
52 }
53
54
55
56 func NewOAuthConfigWithAPIVersion(activeDirectoryEndpoint, tenantID string, apiVersion *string) (*OAuthConfig, error) {
57 if err := validateStringParam(activeDirectoryEndpoint, "activeDirectoryEndpoint"); err != nil {
58 return nil, err
59 }
60 api := ""
61
62 if apiVersion != nil {
63 if err := validateStringParam(*apiVersion, "apiVersion"); err != nil {
64 return nil, err
65 }
66 api = fmt.Sprintf("?api-version=%s", *apiVersion)
67 }
68 u, err := url.Parse(activeDirectoryEndpoint)
69 if err != nil {
70 return nil, err
71 }
72 authorityURL, err := u.Parse(tenantID)
73 if err != nil {
74 return nil, err
75 }
76 authorizeURL, err := u.Parse(fmt.Sprintf(activeDirectoryEndpointTemplate, tenantID, "authorize", api))
77 if err != nil {
78 return nil, err
79 }
80 tokenURL, err := u.Parse(fmt.Sprintf(activeDirectoryEndpointTemplate, tenantID, "token", api))
81 if err != nil {
82 return nil, err
83 }
84 deviceCodeURL, err := u.Parse(fmt.Sprintf(activeDirectoryEndpointTemplate, tenantID, "devicecode", api))
85 if err != nil {
86 return nil, err
87 }
88
89 return &OAuthConfig{
90 AuthorityEndpoint: *authorityURL,
91 AuthorizeEndpoint: *authorizeURL,
92 TokenEndpoint: *tokenURL,
93 DeviceCodeEndpoint: *deviceCodeURL,
94 }, nil
95 }
96
97
98 type MultiTenantOAuthConfig interface {
99 PrimaryTenant() *OAuthConfig
100 AuxiliaryTenants() []*OAuthConfig
101 }
102
103
104 type OAuthOptions struct {
105 APIVersion string
106 }
107
108 func (c OAuthOptions) apiVersion() string {
109 if c.APIVersion != "" {
110 return fmt.Sprintf("?api-version=%s", c.APIVersion)
111 }
112 return "1.0"
113 }
114
115
116
117 func NewMultiTenantOAuthConfig(activeDirectoryEndpoint, primaryTenantID string, auxiliaryTenantIDs []string, options OAuthOptions) (MultiTenantOAuthConfig, error) {
118 if len(auxiliaryTenantIDs) == 0 || len(auxiliaryTenantIDs) > 3 {
119 return nil, errors.New("must specify one to three auxiliary tenants")
120 }
121 mtCfg := multiTenantOAuthConfig{
122 cfgs: make([]*OAuthConfig, len(auxiliaryTenantIDs)+1),
123 }
124 apiVer := options.apiVersion()
125 pri, err := NewOAuthConfigWithAPIVersion(activeDirectoryEndpoint, primaryTenantID, &apiVer)
126 if err != nil {
127 return nil, fmt.Errorf("failed to create OAuthConfig for primary tenant: %v", err)
128 }
129 mtCfg.cfgs[0] = pri
130 for i := range auxiliaryTenantIDs {
131 aux, err := NewOAuthConfig(activeDirectoryEndpoint, auxiliaryTenantIDs[i])
132 if err != nil {
133 return nil, fmt.Errorf("failed to create OAuthConfig for tenant '%s': %v", auxiliaryTenantIDs[i], err)
134 }
135 mtCfg.cfgs[i+1] = aux
136 }
137 return mtCfg, nil
138 }
139
140 type multiTenantOAuthConfig struct {
141
142 cfgs []*OAuthConfig
143 }
144
145 func (m multiTenantOAuthConfig) PrimaryTenant() *OAuthConfig {
146 return m.cfgs[0]
147 }
148
149 func (m multiTenantOAuthConfig) AuxiliaryTenants() []*OAuthConfig {
150 return m.cfgs[1:]
151 }
152
View as plain text