Skip to content

Commit b4261e0

Browse files
Merge pull request #22728 from enj/enj/i/oauth_server_auth
Bug 1703506: Move OAuth server to standard handler chain
2 parents 4457688 + 66e4984 commit b4261e0

4 files changed

Lines changed: 75 additions & 18 deletions

File tree

pkg/cmd/openshift-integrated-oauth-server/server.go

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ package openshift_integrated_oauth_server
33
import (
44
"errors"
55

6+
"k8s.io/apiserver/pkg/authentication/user"
67
genericapiserver "k8s.io/apiserver/pkg/server"
8+
genericapiserveroptions "k8s.io/apiserver/pkg/server/options"
79
"k8s.io/kubernetes/pkg/api/legacyscheme"
810

911
osinv1 "github.com/openshift/api/osin/v1"
@@ -48,20 +50,41 @@ func newOAuthServerConfig(osinConfig *osinv1.OsinServerConfig) (*oauthserver.OAu
4850
// the oauth-server must only run in http1 to avoid http2 connection re-use problems when improperly re-using a wildcard certificate
4951
genericConfig.Config.SecureServing.HTTP1Only = true
5052

53+
authenticationOptions := genericapiserveroptions.NewDelegatingAuthenticationOptions()
54+
authenticationOptions.ClientCert.ClientCA = osinConfig.ServingInfo.ClientCA
55+
authenticationOptions.RemoteKubeConfigFile = osinConfig.KubeClientConfig.KubeConfig
56+
if err := authenticationOptions.ApplyTo(&genericConfig.Authentication, genericConfig.SecureServing, genericConfig.OpenAPIConfig); err != nil {
57+
return nil, err
58+
}
59+
60+
authorizationOptions := genericapiserveroptions.NewDelegatingAuthorizationOptions().
61+
// TODO better formalize / generate this list as trailing * matters
62+
WithAlwaysAllowPaths( // The five sections are:
63+
"/healthz", "/healthz/", // 1. Health checks (root, no wildcard)
64+
"/oauth/*", // 2. OAuth (wildcard)
65+
"/login", "/login/*", // 3. Login (both root and wildcard)
66+
"/logout", "/logout/", // 4. Logout (root, no wildcard)
67+
"/oauth2callback/*", // 5. OAuth callbacks (wildcard)
68+
).
69+
WithAlwaysAllowGroups(user.SystemPrivilegedGroup)
70+
authorizationOptions.RemoteKubeConfigFile = osinConfig.KubeClientConfig.KubeConfig
71+
if err := authorizationOptions.ApplyTo(&genericConfig.Authorization); err != nil {
72+
return nil, err
73+
}
74+
5175
// TODO You need real overrides for rate limiting
5276
kubeClientConfig, err := helpers.GetKubeConfigOrInClusterConfig(osinConfig.KubeClientConfig.KubeConfig, osinConfig.KubeClientConfig.ConnectionOverrides)
5377
if err != nil {
5478
return nil, err
5579
}
5680

57-
oauthServerConfig, err := oauthserver.NewOAuthServerConfig(osinConfig.OAuthConfig, kubeClientConfig)
81+
oauthServerConfig, err := oauthserver.NewOAuthServerConfig(osinConfig.OAuthConfig, kubeClientConfig, genericConfig)
5882
if err != nil {
5983
return nil, err
6084
}
6185

6286
// TODO you probably want to set this
6387
oauthServerConfig.GenericConfig.CorsAllowedOriginList = osinConfig.CORSAllowedOrigins
64-
oauthServerConfig.GenericConfig.SecureServing = genericConfig.SecureServing
6588
//oauthServerConfig.GenericConfig.AuditBackend = genericConfig.AuditBackend
6689
//oauthServerConfig.GenericConfig.AuditPolicyChecker = genericConfig.AuditPolicyChecker
6790

pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/patch_oauthserver.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
// TODO this is taking a very large config for a small piece of it. The information must be broken up at some point so that
1212
// we can run this in a pod. This is an indication of leaky abstraction because it spent too much time in openshift start
1313
func NewOAuthServerConfigFromMasterConfig(genericConfig *genericapiserver.Config, oauthConfig *osinv1.OAuthConfig) (*oauthserver.OAuthServerConfig, error) {
14-
oauthServerConfig, err := oauthserver.NewOAuthServerConfig(*oauthConfig, genericConfig.LoopbackClientConfig)
14+
oauthServerConfig, err := oauthserver.NewOAuthServerConfig(*oauthConfig, genericConfig.LoopbackClientConfig, nil)
1515
if err != nil {
1616
return nil, err
1717
}

pkg/oauthserver/oauthserver/oauth_apiserver.go

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,7 @@ import (
1212
"k8s.io/apimachinery/pkg/runtime/serializer"
1313
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
1414
"k8s.io/apimachinery/pkg/util/wait"
15-
genericapifilters "k8s.io/apiserver/pkg/endpoints/filters"
16-
"k8s.io/apiserver/pkg/features"
1715
genericapiserver "k8s.io/apiserver/pkg/server"
18-
genericfilters "k8s.io/apiserver/pkg/server/filters"
19-
utilfeature "k8s.io/apiserver/pkg/util/feature"
2016
kclientset "k8s.io/client-go/kubernetes"
2117
corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
2218
"k8s.io/client-go/rest"
@@ -47,7 +43,7 @@ func init() {
4743

4844
// TODO we need to switch the oauth server to an external type, but that can be done after we get our externally facing flag values fixed
4945
// TODO remaining bits involve the session file, LDAP util code, validation, ...
50-
func NewOAuthServerConfig(oauthConfig osinv1.OAuthConfig, userClientConfig *rest.Config) (*OAuthServerConfig, error) {
46+
func NewOAuthServerConfig(oauthConfig osinv1.OAuthConfig, userClientConfig *rest.Config, genericConfig *genericapiserver.RecommendedConfig) (*OAuthServerConfig, error) {
5147
// TODO: there is probably some better way to do this
5248
decoder := codecs.UniversalDecoder(osinv1.GroupVersion)
5349
for i, idp := range oauthConfig.IdentityProviders {
@@ -62,7 +58,11 @@ func NewOAuthServerConfig(oauthConfig osinv1.OAuthConfig, userClientConfig *rest
6258
oauthConfig.IdentityProviders[i].Provider.Object = idpObject
6359
}
6460

65-
genericConfig := genericapiserver.NewRecommendedConfig(codecs)
61+
// this leaves the embedded OAuth server code path alone
62+
if genericConfig == nil {
63+
genericConfig = genericapiserver.NewRecommendedConfig(codecs)
64+
}
65+
6666
genericConfig.LoopbackClientConfig = userClientConfig
6767

6868
userClient, err := userclient.NewForConfig(userClientConfig)
@@ -277,21 +277,26 @@ func (c completedOAuthConfig) New(delegationTarget genericapiserver.DelegationTa
277277
}
278278

279279
func (c *OAuthServerConfig) buildHandlerChainForOAuth(startingHandler http.Handler, genericConfig *genericapiserver.Config) http.Handler {
280+
// add OAuth handlers on top of the generic API server handlers
280281
handler, err := c.WithOAuth(startingHandler)
281282
if err != nil {
282-
// the existing errors all cause the server to die anyway
283+
// the existing errors all cause the OAuth server to die anyway
283284
panic(err)
284285
}
285-
if utilfeature.DefaultFeatureGate.Enabled(features.AdvancedAuditing) {
286-
handler = genericapifilters.WithAudit(handler, genericConfig.AuditBackend, genericConfig.AuditPolicyChecker, genericConfig.LongRunningFunc)
287-
}
288286

289-
handler = genericfilters.WithMaxInFlightLimit(handler, genericConfig.MaxRequestsInFlight, genericConfig.MaxMutatingRequestsInFlight, genericConfig.LongRunningFunc)
290-
handler = genericfilters.WithCORS(handler, genericConfig.CorsAllowedOriginList, nil, nil, nil, "true")
291-
handler = genericfilters.WithTimeoutForNonLongRunningRequests(handler, genericConfig.LongRunningFunc, genericConfig.RequestTimeout)
292-
handler = genericapifilters.WithRequestInfo(handler, genericapiserver.NewRequestInfoResolver(genericConfig))
287+
// add back the Authorization header so that WithOAuth can use it even after WithAuthentication deletes it
288+
// WithOAuth sees users' passwords and can mint tokens so this is not really an issue
289+
handler = headers.WithRestoreAuthorizationHeader(handler)
290+
291+
// this is the normal kube handler chain
292+
handler = genericapiserver.DefaultBuildHandlerChain(handler, genericConfig)
293+
294+
// store a copy of the Authorization header for later use
295+
handler = headers.WithPreserveAuthorizationHeader(handler)
296+
297+
// protected endpoints should not be cached
293298
handler = headers.WithStandardHeaders(handler)
294-
handler = genericfilters.WithPanicRecovery(handler)
299+
295300
return handler
296301
}
297302

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package headers
2+
3+
import "net/http"
4+
5+
const (
6+
authzHeader = "Authorization"
7+
copyAuthzHeader = "oauth.openshift.io:" + authzHeader // will never conflict because : is not a valid header key
8+
)
9+
10+
func WithPreserveAuthorizationHeader(handler http.Handler) http.Handler {
11+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
12+
if vv, ok := r.Header[authzHeader]; ok {
13+
r.Header[copyAuthzHeader] = vv // capture the values before they are deleted
14+
}
15+
16+
handler.ServeHTTP(w, r)
17+
})
18+
}
19+
20+
func WithRestoreAuthorizationHeader(handler http.Handler) http.Handler {
21+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
22+
if vv, ok := r.Header[copyAuthzHeader]; ok {
23+
r.Header[authzHeader] = vv // add them back afterwards for use in OAuth flows
24+
delete(r.Header, copyAuthzHeader)
25+
}
26+
27+
handler.ServeHTTP(w, r)
28+
})
29+
}

0 commit comments

Comments
 (0)