Skip to content

Commit

Permalink
added option to handle OAuth grants at a per-client granularity
Browse files Browse the repository at this point in the history
  • Loading branch information
stevekuznetsov committed Mar 11, 2016
1 parent b818f26 commit 046f655
Show file tree
Hide file tree
Showing 11 changed files with 80 additions and 117 deletions.
6 changes: 6 additions & 0 deletions api/swagger-spec/oapi-v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -21600,6 +21600,9 @@
"v1.OAuthClient": {
"id": "v1.OAuthClient",
"description": "OAuthClient describes an OAuth client",
"required": [
"grantStrategy"
],
"properties": {
"kind": {
"type": "string",
Expand Down Expand Up @@ -21627,6 +21630,9 @@
"type": "string"
},
"description": "RedirectURIs is the valid redirection URIs associated with a client"
},
"grantStrategy": {
"type": "string"
}
}
},
Expand Down
1 change: 1 addition & 0 deletions pkg/api/deep_copy_generated.go
Original file line number Diff line number Diff line change
Expand Up @@ -2609,6 +2609,7 @@ func deepCopy_api_OAuthClient(in oauthapi.OAuthClient, out *oauthapi.OAuthClient
} else {
out.RedirectURIs = nil
}
out.GrantStrategy = in.GrantStrategy
return nil
}

Expand Down
2 changes: 2 additions & 0 deletions pkg/api/v1/conversion_generated.go
Original file line number Diff line number Diff line change
Expand Up @@ -4802,6 +4802,7 @@ func autoConvert_api_OAuthClient_To_v1_OAuthClient(in *oauthapi.OAuthClient, out
} else {
out.RedirectURIs = nil
}
out.GrantStrategy = serverapiv1.GrantHandlerType(in.GrantStrategy)
return nil
}

Expand Down Expand Up @@ -5004,6 +5005,7 @@ func autoConvert_v1_OAuthClient_To_api_OAuthClient(in *oauthapiv1.OAuthClient, o
} else {
out.RedirectURIs = nil
}
out.GrantStrategy = serverapi.GrantHandlerType(in.GrantStrategy)
return nil
}

Expand Down
1 change: 1 addition & 0 deletions pkg/api/v1/deep_copy_generated.go
Original file line number Diff line number Diff line change
Expand Up @@ -2496,6 +2496,7 @@ func deepCopy_v1_OAuthClient(in oauthapiv1.OAuthClient, out *oauthapiv1.OAuthCli
} else {
out.RedirectURIs = nil
}
out.GrantStrategy = in.GrantStrategy
return nil
}

Expand Down
100 changes: 0 additions & 100 deletions pkg/api/v1beta3/conversion_generated.go
Original file line number Diff line number Diff line change
Expand Up @@ -3477,30 +3477,6 @@ func Convert_api_OAuthAuthorizeTokenList_To_v1beta3_OAuthAuthorizeTokenList(in *
return autoConvert_api_OAuthAuthorizeTokenList_To_v1beta3_OAuthAuthorizeTokenList(in, out, s)
}

func autoConvert_api_OAuthClient_To_v1beta3_OAuthClient(in *oauthapi.OAuthClient, out *oauthapiv1beta3.OAuthClient, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*oauthapi.OAuthClient))(in)
}
if err := Convert_api_ObjectMeta_To_v1beta3_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, s); err != nil {
return err
}
out.Secret = in.Secret
out.RespondWithChallenges = in.RespondWithChallenges
if in.RedirectURIs != nil {
out.RedirectURIs = make([]string, len(in.RedirectURIs))
for i := range in.RedirectURIs {
out.RedirectURIs[i] = in.RedirectURIs[i]
}
} else {
out.RedirectURIs = nil
}
return nil
}

func Convert_api_OAuthClient_To_v1beta3_OAuthClient(in *oauthapi.OAuthClient, out *oauthapiv1beta3.OAuthClient, s conversion.Scope) error {
return autoConvert_api_OAuthClient_To_v1beta3_OAuthClient(in, out, s)
}

func autoConvert_api_OAuthClientAuthorization_To_v1beta3_OAuthClientAuthorization(in *oauthapi.OAuthClientAuthorization, out *oauthapiv1beta3.OAuthClientAuthorization, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*oauthapi.OAuthClientAuthorization))(in)
Expand Down Expand Up @@ -3550,30 +3526,6 @@ func Convert_api_OAuthClientAuthorizationList_To_v1beta3_OAuthClientAuthorizatio
return autoConvert_api_OAuthClientAuthorizationList_To_v1beta3_OAuthClientAuthorizationList(in, out, s)
}

func autoConvert_api_OAuthClientList_To_v1beta3_OAuthClientList(in *oauthapi.OAuthClientList, out *oauthapiv1beta3.OAuthClientList, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*oauthapi.OAuthClientList))(in)
}
if err := api.Convert_unversioned_ListMeta_To_unversioned_ListMeta(&in.ListMeta, &out.ListMeta, s); err != nil {
return err
}
if in.Items != nil {
out.Items = make([]oauthapiv1beta3.OAuthClient, len(in.Items))
for i := range in.Items {
if err := Convert_api_OAuthClient_To_v1beta3_OAuthClient(&in.Items[i], &out.Items[i], s); err != nil {
return err
}
}
} else {
out.Items = nil
}
return nil
}

func Convert_api_OAuthClientList_To_v1beta3_OAuthClientList(in *oauthapi.OAuthClientList, out *oauthapiv1beta3.OAuthClientList, s conversion.Scope) error {
return autoConvert_api_OAuthClientList_To_v1beta3_OAuthClientList(in, out, s)
}

func autoConvert_v1beta3_OAuthAccessToken_To_api_OAuthAccessToken(in *oauthapiv1beta3.OAuthAccessToken, out *oauthapi.OAuthAccessToken, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*oauthapiv1beta3.OAuthAccessToken))(in)
Expand Down Expand Up @@ -3679,30 +3631,6 @@ func Convert_v1beta3_OAuthAuthorizeTokenList_To_api_OAuthAuthorizeTokenList(in *
return autoConvert_v1beta3_OAuthAuthorizeTokenList_To_api_OAuthAuthorizeTokenList(in, out, s)
}

func autoConvert_v1beta3_OAuthClient_To_api_OAuthClient(in *oauthapiv1beta3.OAuthClient, out *oauthapi.OAuthClient, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*oauthapiv1beta3.OAuthClient))(in)
}
if err := Convert_v1beta3_ObjectMeta_To_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, s); err != nil {
return err
}
out.Secret = in.Secret
out.RespondWithChallenges = in.RespondWithChallenges
if in.RedirectURIs != nil {
out.RedirectURIs = make([]string, len(in.RedirectURIs))
for i := range in.RedirectURIs {
out.RedirectURIs[i] = in.RedirectURIs[i]
}
} else {
out.RedirectURIs = nil
}
return nil
}

func Convert_v1beta3_OAuthClient_To_api_OAuthClient(in *oauthapiv1beta3.OAuthClient, out *oauthapi.OAuthClient, s conversion.Scope) error {
return autoConvert_v1beta3_OAuthClient_To_api_OAuthClient(in, out, s)
}

func autoConvert_v1beta3_OAuthClientAuthorization_To_api_OAuthClientAuthorization(in *oauthapiv1beta3.OAuthClientAuthorization, out *oauthapi.OAuthClientAuthorization, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*oauthapiv1beta3.OAuthClientAuthorization))(in)
Expand Down Expand Up @@ -3752,30 +3680,6 @@ func Convert_v1beta3_OAuthClientAuthorizationList_To_api_OAuthClientAuthorizatio
return autoConvert_v1beta3_OAuthClientAuthorizationList_To_api_OAuthClientAuthorizationList(in, out, s)
}

func autoConvert_v1beta3_OAuthClientList_To_api_OAuthClientList(in *oauthapiv1beta3.OAuthClientList, out *oauthapi.OAuthClientList, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*oauthapiv1beta3.OAuthClientList))(in)
}
if err := api.Convert_unversioned_ListMeta_To_unversioned_ListMeta(&in.ListMeta, &out.ListMeta, s); err != nil {
return err
}
if in.Items != nil {
out.Items = make([]oauthapi.OAuthClient, len(in.Items))
for i := range in.Items {
if err := Convert_v1beta3_OAuthClient_To_api_OAuthClient(&in.Items[i], &out.Items[i], s); err != nil {
return err
}
}
} else {
out.Items = nil
}
return nil
}

func Convert_v1beta3_OAuthClientList_To_api_OAuthClientList(in *oauthapiv1beta3.OAuthClientList, out *oauthapi.OAuthClientList, s conversion.Scope) error {
return autoConvert_v1beta3_OAuthClientList_To_api_OAuthClientList(in, out, s)
}

func autoConvert_api_Project_To_v1beta3_Project(in *projectapi.Project, out *projectapiv1beta3.Project, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*projectapi.Project))(in)
Expand Down Expand Up @@ -6684,8 +6588,6 @@ func init() {
autoConvert_api_OAuthAuthorizeToken_To_v1beta3_OAuthAuthorizeToken,
autoConvert_api_OAuthClientAuthorizationList_To_v1beta3_OAuthClientAuthorizationList,
autoConvert_api_OAuthClientAuthorization_To_v1beta3_OAuthClientAuthorization,
autoConvert_api_OAuthClientList_To_v1beta3_OAuthClientList,
autoConvert_api_OAuthClient_To_v1beta3_OAuthClient,
autoConvert_api_ObjectFieldSelector_To_v1beta3_ObjectFieldSelector,
autoConvert_api_ObjectMeta_To_v1beta3_ObjectMeta,
autoConvert_api_ObjectReference_To_v1beta3_ObjectReference,
Expand Down Expand Up @@ -6825,8 +6727,6 @@ func init() {
autoConvert_v1beta3_OAuthAuthorizeToken_To_api_OAuthAuthorizeToken,
autoConvert_v1beta3_OAuthClientAuthorizationList_To_api_OAuthClientAuthorizationList,
autoConvert_v1beta3_OAuthClientAuthorization_To_api_OAuthClientAuthorization,
autoConvert_v1beta3_OAuthClientList_To_api_OAuthClientList,
autoConvert_v1beta3_OAuthClient_To_api_OAuthClient,
autoConvert_v1beta3_ObjectFieldSelector_To_api_ObjectFieldSelector,
autoConvert_v1beta3_ObjectMeta_To_api_ObjectMeta,
autoConvert_v1beta3_ObjectReference_To_api_ObjectReference,
Expand Down
49 changes: 48 additions & 1 deletion pkg/auth/oauth/handlers/grant.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ package handlers

import (
"errors"
"fmt"
"net/http"
"net/url"

"github.com/RangelReale/osin"

"github.com/openshift/origin/pkg/auth/api"
"k8s.io/kubernetes/pkg/auth/user"

"github.com/openshift/origin/pkg/auth/api"
configapi "github.com/openshift/origin/pkg/cmd/server/api"
oauthapi "github.com/openshift/origin/pkg/oauth/api"
)

// GrantCheck implements osinserver.AuthorizeHandler to ensure requested scopes have been authorized
Expand Down Expand Up @@ -122,3 +126,46 @@ func (g *redirectGrant) GrantNeeded(user user.Info, grant *api.Grant, w http.Res
http.Redirect(w, req, redirectURL.String(), http.StatusFound)
return false, true, nil
}

// NewPerClientGrant returns a grant handler that determines what to do based on the grant strategy in the client
func NewPerClientGrant(prompt GrantHandler, defaultStrategy configapi.GrantHandlerType) GrantHandler {
return &perClientGrant{
auto: NewAutoGrant(),
prompt: prompt,
deny: NewEmptyGrant(),
defaultStrategy: defaultStrategy,
}
}

type perClientGrant struct {
auto GrantHandler
prompt GrantHandler
deny GrantHandler
defaultStrategy configapi.GrantHandlerType
}

func (g *perClientGrant) GrantNeeded(user user.Info, grant *api.Grant, w http.ResponseWriter, req *http.Request) (bool, bool, error) {
client, ok := grant.Client.GetUserData().(*oauthapi.OAuthClient)
if !ok {
return false, false, errors.New("unrecognized OAuth client type")
}

strategy := client.GrantStrategy
if len(strategy) == 0 {
strategy = g.defaultStrategy
}

switch strategy {
case configapi.GrantHandlerAuto:
return g.auto.GrantNeeded(user, grant, w, req)

case configapi.GrantHandlerPrompt:
return g.prompt.GrantNeeded(user, grant, w, req)

case configapi.GrantHandlerDeny:
return g.deny.GrantNeeded(user, grant, w, req)

default:
return false, false, fmt.Errorf("OAuth client grant strategy %q unrecognized", strategy)
}
}
4 changes: 3 additions & 1 deletion pkg/cmd/server/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -795,7 +795,9 @@ type OpenIDClaims struct {
}

type GrantConfig struct {
// Method: allow, deny, prompt
// Method determines the default strategy to use when an OAuth client requests a grant.
// This method will be used only if the specific OAuth client doesn't provide a strategy
// of their own.
Method GrantHandlerType
}

Expand Down
21 changes: 6 additions & 15 deletions pkg/cmd/server/origin/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,23 +313,14 @@ func (c *AuthConfig) getAuthorizeAuthenticationHandlers(mux cmdutil.Mux, errorHa

// getGrantHandler returns the object that handles approving or rejecting grant requests
func (c *AuthConfig) getGrantHandler(mux cmdutil.Mux, auth authenticator.Request, clientregistry clientregistry.Registry, authregistry clientauthregistry.Registry) handlers.GrantHandler {
switch c.Options.GrantConfig.Method {
case configapi.GrantHandlerDeny:
return handlers.NewEmptyGrant()

case configapi.GrantHandlerAuto:
return handlers.NewAutoGrant()

case configapi.GrantHandlerPrompt:
grantServer := grant.NewGrant(c.getCSRF(), auth, grant.DefaultFormRenderer, clientregistry, authregistry)
grantServer.Install(mux, OpenShiftApprovePrefix)
return handlers.NewRedirectGrant(OpenShiftApprovePrefix)

default:
glog.Fatalf("No grant handler found that matches %v. The oauth server cannot start!", c.Options.GrantConfig.Method)
// check that the global default strategy is something we honor
if !configapi.ValidGrantHandlerTypes.Has(string(c.Options.GrantConfig.Method)) {
glog.Fatalf("No grant handler found that matches %v. The OAuth server cannot start!", c.Options.GrantConfig.Method)
}

return nil
grantServer := grant.NewGrant(c.getCSRF(), auth, grant.DefaultFormRenderer, clientregistry, authregistry)
grantServer.Install(mux, OpenShiftApprovePrefix)
return handlers.NewPerClientGrant(handlers.NewRedirectGrant(OpenShiftApprovePrefix), c.Options.GrantConfig.Method)
}

// getAuthenticationFinalizer returns an authentication finalizer which is called just prior to writing a response to an authorization request
Expand Down
6 changes: 6 additions & 0 deletions pkg/oauth/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package api
import (
kapi "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"

configapi "github.com/openshift/origin/pkg/cmd/server/api"
)

type OAuthAccessToken struct {
Expand Down Expand Up @@ -73,6 +75,10 @@ type OAuthClient struct {

// RedirectURIs is the valid redirection URIs associated with a client
RedirectURIs []string

// GrantStrategy determines how to handle grants for this client. If no method is provided, the
// cluster default grant handling method will be used
GrantStrategy configapi.GrantHandlerType
}

type OAuthClientAuthorization struct {
Expand Down
1 change: 1 addition & 0 deletions pkg/oauth/api/v1/swagger_doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ var map_OAuthClient = map[string]string{
"secret": "Secret is the unique secret associated with a client",
"respondWithChallenges": "RespondWithChallenges indicates whether the client wants authentication needed responses made in the form of challenges instead of redirects",
"redirectURIs": "RedirectURIs is the valid redirection URIs associated with a client",
"grantStrategy": "GrantStrategy determines how to handle grants for this client. If no method is provided, the cluster default grant handling method will be used",
}

func (OAuthClient) SwaggerDoc() map[string]string {
Expand Down
6 changes: 6 additions & 0 deletions pkg/oauth/api/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package v1
import (
"k8s.io/kubernetes/pkg/api/unversioned"
kapi "k8s.io/kubernetes/pkg/api/v1"

configapi "github.com/openshift/origin/pkg/cmd/server/api/v1"
)

// OAuthAccessToken describes an OAuth access token
Expand Down Expand Up @@ -79,6 +81,10 @@ type OAuthClient struct {

// RedirectURIs is the valid redirection URIs associated with a client
RedirectURIs []string `json:"redirectURIs,omitempty" description:"valid redirection URIs associated with a client"`

// GrantStrategy determines how to handle grants for this client. If no method is provided, the
// cluster default grant handling method will be used
GrantStrategy configapi.GrantHandlerType `json:"grantStrategy,omitempty"`
}

// OAuthClientAuthorization describes an authorization created by an OAuth client
Expand Down

0 comments on commit 046f655

Please sign in to comment.