forked from openshift/origin
/
patch_handlerchain.go
114 lines (95 loc) · 4.21 KB
/
patch_handlerchain.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
package openshiftkubeapiserver
import (
"net/http"
"strings"
"k8s.io/klog"
genericapiserver "k8s.io/apiserver/pkg/server"
kubecontrolplanev1 "github.com/openshift/api/kubecontrolplane/v1"
osinv1 "github.com/openshift/api/osin/v1"
"github.com/openshift/origin/pkg/cmd/openshift-apiserver/openshiftapiserver/configprocessing"
"github.com/openshift/origin/pkg/oauth/urls"
"github.com/openshift/origin/pkg/oauth/util"
"github.com/openshift/origin/pkg/util/httprequest"
)
const (
openShiftOAuthAPIPrefix = "/oauth"
openShiftLoginPrefix = "/login"
openShiftLogoutPrefix = "/logout"
openShiftOAuthCallbackPrefix = "/oauth2callback"
)
// TODO switch back to taking a kubeapiserver config. For now make it obviously safe for 3.11
func BuildHandlerChain(genericConfig *genericapiserver.Config, oauthConfig *osinv1.OAuthConfig, authConfig kubecontrolplanev1.MasterAuthConfig, userAgentMatchingConfig kubecontrolplanev1.UserAgentMatchingConfig, consolePublicURL string) (func(apiHandler http.Handler, kc *genericapiserver.Config) http.Handler, map[string]genericapiserver.PostStartHookFunc, error) {
// ignore oauthConfig if we have a valid OAuth metadata file
// this prevents us from running the internal OAuth server when we are honoring an external one
if oauthMetadataFile := authConfig.OAuthMetadataFile; len(oauthMetadataFile) > 0 {
if _, _, err := util.LoadOAuthMetadataFile(oauthMetadataFile); err == nil {
oauthConfig = nil // simplest way to keep existing code paths working
}
}
extraPostStartHooks := map[string]genericapiserver.PostStartHookFunc{}
var oauthServerHandler http.Handler
if oauthConfig != nil {
var newPostStartHooks map[string]genericapiserver.PostStartHookFunc
var err error
oauthServerHandler, newPostStartHooks, err = NewOAuthServerHandler(genericConfig, oauthConfig)
if err != nil {
return nil, nil, err
}
for name, fn := range newPostStartHooks {
extraPostStartHooks[name] = fn
}
}
return func(apiHandler http.Handler, genericConfig *genericapiserver.Config) http.Handler {
// these are after the kube handler
handler := versionSkewFilter(apiHandler, userAgentMatchingConfig)
// this is the normal kube handler chain
handler = genericapiserver.DefaultBuildHandlerChain(handler, genericConfig)
// these handlers are all before the normal kube chain
handler = translateLegacyScopeImpersonation(handler)
handler = configprocessing.WithCacheControl(handler, "no-store") // protected endpoints should not be cached
// redirects from / and /console to consolePublicURL if you're using a browser
handler = withConsoleRedirect(handler, consolePublicURL)
if oauthConfig != nil {
// these handlers are actually separate API servers which have their own handler chains.
// our server embeds these
handler = withOAuthRedirection(oauthConfig, handler, oauthServerHandler)
}
return handler
},
extraPostStartHooks,
nil
}
func withOAuthRedirection(oauthConfig *osinv1.OAuthConfig, handler, oauthServerHandler http.Handler) http.Handler {
if oauthConfig == nil {
return handler
}
klog.Infof("Starting OAuth2 API at %s", urls.OpenShiftOAuthAPIPrefix)
return WithPatternPrefixHandler(handler, oauthServerHandler, openShiftOAuthAPIPrefix, openShiftLoginPrefix, openShiftLogoutPrefix, openShiftOAuthCallbackPrefix)
}
func WithPatternPrefixHandler(handler http.Handler, patternHandler http.Handler, prefixes ...string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
for _, p := range prefixes {
if strings.HasPrefix(req.URL.Path, p) {
patternHandler.ServeHTTP(w, req)
return
}
}
handler.ServeHTTP(w, req)
})
}
// If we know the location of the asset server, redirect to it when / is requested
// and the Accept header supports text/html
func withConsoleRedirect(handler http.Handler, consolePublicURL string) http.Handler {
if len(consolePublicURL) == 0 {
return handler
}
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
if strings.HasPrefix(req.URL.Path, "/console") ||
(req.URL.Path == "/" && httprequest.PrefersHTML(req)) {
http.Redirect(w, req, consolePublicURL, http.StatusFound)
return
}
// Dispatch to the next handler
handler.ServeHTTP(w, req)
})
}