Skip to content

Commit 18cca83

Browse files
committed
Add Validation for External OAuth Config
1 parent da36041 commit 18cca83

File tree

3 files changed

+127
-1
lines changed

3 files changed

+127
-1
lines changed

pkg/cmd/server/apis/config/validation/master.go

+23-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
configapi "github.com/openshift/origin/pkg/cmd/server/apis/config"
2626
"github.com/openshift/origin/pkg/cmd/server/bootstrappolicy"
2727
"github.com/openshift/origin/pkg/cmd/server/cm"
28+
oauthutil "github.com/openshift/origin/pkg/oauth/util"
2829
"github.com/openshift/origin/pkg/security/mcs"
2930
"github.com/openshift/origin/pkg/security/uid"
3031
"github.com/openshift/origin/pkg/util/labelselector"
@@ -144,7 +145,12 @@ func ValidateMasterConfig(config *configapi.MasterConfig, fldPath *field.Path) V
144145
if config.OAuthConfig != nil {
145146
validationResults.Append(ValidateOAuthConfig(config.OAuthConfig, fldPath.Child("oauthConfig")))
146147
}
147-
148+
if config.ExternalOAuthConfig != nil {
149+
if config.OAuthConfig != nil {
150+
validationResults.AddErrors(field.Invalid(fldPath.Child("externalOAuthConfig"), config.ExternalOAuthConfig, "Cannot specify External OAuth Config when the internal Oauth Server is configured"))
151+
}
152+
validationResults.Append(ValidateExternalOAuthConfig(config.ExternalOAuthConfig, fldPath.Child("externalOAuthConfig")))
153+
}
148154
validationResults.Append(ValidateServiceAccountConfig(config.ServiceAccountConfig, builtInKubernetes, fldPath.Child("serviceAccountConfig")))
149155

150156
validationResults.Append(ValidateHTTPServingInfo(config.ServingInfo, fldPath.Child("servingInfo")))
@@ -750,3 +756,19 @@ func ValidateDeprecatedClusterNetworkConfig(config *configapi.MasterConfig, fldP
750756
}
751757
return validationResults
752758
}
759+
760+
func ValidateExternalOAuthConfig(config *configapi.ExternalOAuthConfig, fldPath *field.Path) ValidationResults {
761+
validationResults := ValidationResults{}
762+
763+
_, err := oauthutil.LoadOAuthMetadataFile(config.MetadataFile)
764+
if err != nil {
765+
validationResults.AddErrors(field.Invalid(fldPath.Child("metadataFile"), config.MetadataFile, fmt.Sprintf("Metadata validation failed: %v", err)))
766+
}
767+
if _, urlErrs := ValidateURL(config.MasterPublicURL, fldPath.Child("masterPublicURL")); len(urlErrs) > 0 {
768+
validationResults.AddErrors(urlErrs...)
769+
}
770+
if _, urlErrs := ValidateURL(config.AssetPublicURL, fldPath.Child("assetPublicURL")); len(urlErrs) > 0 {
771+
validationResults.AddErrors(urlErrs...)
772+
}
773+
return validationResults
774+
}

pkg/cmd/server/apis/config/validation/master_test.go

+77
Original file line numberDiff line numberDiff line change
@@ -611,3 +611,80 @@ func TestValidateMasterAuthConfig(t *testing.T) {
611611
}
612612
}
613613
}
614+
615+
var testMetadataContent = []byte(`{
616+
"issuer": "https://127.0.0.1/",
617+
"authorization_endpoint": "https://127.0.0.1/",
618+
"token_endpoint": "https://127.0.0.1/",
619+
"scopes_supported": ["openid", "profile", "email", "address", "phone", "offline_access"],
620+
"response_types_supported": ["code", "code token"],
621+
"grant_types_supported": ["authorization_code", "implicit"],
622+
"code_challenge_methods_supported": ["plain", "S256"]}`)
623+
624+
func TestValidateExternalOAuthConfig(t *testing.T) {
625+
metadataFile, err := ioutil.TempFile("", "oauth.metadata")
626+
if err != nil {
627+
t.Fatalf("unexpected error: %v", err)
628+
}
629+
defer os.Remove(metadataFile.Name())
630+
ioutil.WriteFile(metadataFile.Name(), testMetadataContent, os.FileMode(0644))
631+
badMetadataFile, err := ioutil.TempFile("", "badoauth.metadata")
632+
if err != nil {
633+
t.Fatalf("unexpected error: %v", err)
634+
}
635+
defer os.Remove(badMetadataFile.Name())
636+
ioutil.WriteFile(badMetadataFile.Name(), []byte("bad file"), os.FileMode(0644))
637+
testCases := []struct {
638+
name string
639+
config *configapi.ExternalOAuthConfig
640+
errors []string
641+
}{
642+
{
643+
name: "No Metadata file",
644+
config: &configapi.ExternalOAuthConfig{
645+
MetadataFile: "NoFile",
646+
MasterPublicURL: "https://127.0.0.1/",
647+
AssetPublicURL: "https://127.0.0.1/",
648+
},
649+
errors: []string{"Metadata validation failed: Unable to read External OAuth Metadata file: open NoFile: no such file or directory"},
650+
},
651+
{
652+
name: "Bad Metadata file",
653+
config: &configapi.ExternalOAuthConfig{
654+
MetadataFile: badMetadataFile.Name(),
655+
MasterPublicURL: "https://127.0.0.1/",
656+
AssetPublicURL: "https://127.0.0.1/",
657+
},
658+
errors: []string{"Metadata validation failed: Unable to decode External OAuth Metadata file: invalid character 'b' looking for beginning of value"},
659+
},
660+
{
661+
name: "Bad Master Public URL",
662+
config: &configapi.ExternalOAuthConfig{
663+
MetadataFile: metadataFile.Name(),
664+
MasterPublicURL: "bad",
665+
AssetPublicURL: "https://127.0.0.1/",
666+
},
667+
errors: []string{"must contain a scheme (e.g. https://)", "must contain a host"},
668+
},
669+
{
670+
name: "Bad Asset Public URL",
671+
config: &configapi.ExternalOAuthConfig{
672+
MetadataFile: metadataFile.Name(),
673+
MasterPublicURL: "https://127.0.0.1/",
674+
AssetPublicURL: "bad",
675+
},
676+
errors: []string{"must contain a scheme (e.g. https://)", "must contain a host"},
677+
},
678+
}
679+
for _, test := range testCases {
680+
results := ValidateExternalOAuthConfig(test.config, nil)
681+
actualErrors := sets.NewString()
682+
expectedErrors := sets.NewString(test.errors...)
683+
for i := range results.Errors {
684+
actualErrors.Insert(results.Errors[i].Detail)
685+
}
686+
if !expectedErrors.Equal(actualErrors) {
687+
t.Errorf("Expected errors: %v, actual errors: %v", expectedErrors, actualErrors)
688+
}
689+
}
690+
}

pkg/oauth/util/discovery.go

+27
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"encoding/json"
55
"fmt"
66
"io/ioutil"
7+
"net/url"
78

89
"github.com/RangelReale/osin"
910
"github.com/openshift/origin/pkg/authorization/authorizer/scope"
@@ -56,6 +57,20 @@ func GetOauthMetadata(masterPublicURL string) OauthAuthorizationServerMetadata {
5657
}
5758
}
5859

60+
func validateURL(urlString string) error {
61+
urlObj, err := url.Parse(urlString)
62+
if err != nil {
63+
return fmt.Errorf("%q is an invalid URL: %v", urlString, err)
64+
}
65+
if urlObj.Scheme != "https" {
66+
return fmt.Errorf("must use https scheme")
67+
}
68+
if len(urlObj.Host) == 0 {
69+
return fmt.Errorf("must contain a valid host")
70+
}
71+
return nil
72+
}
73+
5974
func LoadOAuthMetadataFile(metadataFile string) ([]byte, error) {
6075
data, err := ioutil.ReadFile(metadataFile)
6176
if err != nil {
@@ -67,5 +82,17 @@ func LoadOAuthMetadataFile(metadataFile string) ([]byte, error) {
6782
return nil, fmt.Errorf("Unable to decode External OAuth Metadata file: %v", err)
6883
}
6984

85+
if err := validateURL(oauthMetadata.Issuer); err != nil {
86+
return nil, fmt.Errorf("Error validating External OAuth Metadata Issuer field: %v", err)
87+
}
88+
89+
if err := validateURL(oauthMetadata.AuthorizationEndpoint); err != nil {
90+
return nil, fmt.Errorf("Error validating External OAuth Metadata AuthorizationEndpoint field: %v", err)
91+
}
92+
93+
if err := validateURL(oauthMetadata.TokenEndpoint); err != nil {
94+
return nil, fmt.Errorf("Error validating External OAuth Metadata TokenEndpoint field: %v", err)
95+
}
96+
7097
return data, nil
7198
}

0 commit comments

Comments
 (0)