/
admin_api.go
119 lines (102 loc) · 2.88 KB
/
admin_api.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
package service
import (
"fmt"
"net/http"
"net/url"
"github.com/authgear/authgear-server/pkg/lib/config"
"github.com/authgear/authgear-server/pkg/lib/config/configsource"
portalconfig "github.com/authgear/authgear-server/pkg/portal/config"
)
type AuthzAdder interface {
AddAuthz(
auth config.AdminAPIAuth,
appID config.AppID,
authKey *config.AdminAPIAuthKey,
auditContext interface{},
hdr http.Header) (err error)
}
type AdminAPIDefaultDomainService interface {
GetLatestAppHost(appID string) (string, error)
}
type AdminAPIService struct {
AuthgearConfig *portalconfig.AuthgearConfig
AdminAPIConfig *portalconfig.AdminAPIConfig
ConfigSource *configsource.ConfigSource
AuthzAdder AuthzAdder
DefaultDomains AdminAPIDefaultDomainService
}
type Usage string
const (
UsageProxy Usage = "proxy"
UsageInternal Usage = "internal"
)
type PortalAdminAPIAuthContext struct {
Usage Usage `json:"usage"`
ActorUserID string `json:"actor_user_id,omitempty"`
HTTPReferer string `json:"http_referer,omitempty"`
}
func (s *AdminAPIService) ResolveConfig(appID string) (*config.Config, error) {
appCtx, err := s.ConfigSource.ContextResolver.ResolveContext(appID)
if err != nil {
return nil, err
}
return appCtx.Config, nil
}
func (s *AdminAPIService) ResolveEndpoint(appID string) (*url.URL, error) {
switch s.AdminAPIConfig.Type {
case portalconfig.AdminAPITypeStatic:
endpoint, err := url.Parse(s.AdminAPIConfig.Endpoint)
if err != nil {
return nil, err
}
return endpoint, nil
default:
panic(fmt.Errorf("portal: unexpected admin API type: %v", s.AdminAPIConfig.Type))
}
}
func (s *AdminAPIService) Director(appID string, p string, actorUserID string, usage Usage) (director func(*http.Request), err error) {
cfg, err := s.ResolveConfig(appID)
if err != nil {
return
}
authKey, ok := cfg.SecretConfig.LookupData(config.AdminAPIAuthKeyKey).(*config.AdminAPIAuthKey)
if !ok {
err = fmt.Errorf("failed to look up admin API auth key: %v", appID)
return
}
endpoint, err := s.ResolveEndpoint(appID)
if err != nil {
return
}
endpoint.Path = p
host, err := s.DefaultDomains.GetLatestAppHost(appID)
if err != nil {
return
}
director = func(r *http.Request) {
// It is important to preserve raw query so that GraphiQL ?query=... is not broken.
rawQuery := r.URL.RawQuery
r.URL = endpoint
r.URL.RawQuery = rawQuery
r.Host = host
r.Header.Set("X-Forwarded-Host", r.Host)
err = s.AuthzAdder.AddAuthz(
s.AdminAPIConfig.Auth,
config.AppID(appID),
authKey,
PortalAdminAPIAuthContext{
Usage: usage,
ActorUserID: actorUserID,
HTTPReferer: r.Header.Get("Referer"),
},
r.Header,
)
if err != nil {
panic(err)
}
}
return
}
func (s *AdminAPIService) SelfDirector(actorUserID string, usage Usage) (director func(*http.Request), err error) {
return s.Director(s.AuthgearConfig.AppID, "/graphql", actorUserID, usage)
}