package validation
import (
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/util/validation/field"
oapi "github.com/openshift/origin/pkg/oauth/api"
)
func TestValidateRedirectURI(t *testing.T) {
allowed := []string{
// Empty allowed
"",
// Non-absolute
"server",
// No protocol
"//server",
// Case insensitive
"HTTP://server",
"HTTPS://server",
// Normal paths
"https://server",
"https://server",
// With ports
"https://server:",
"https://server:port",
// With or without paths, with or without trailing slashes
"https://server:port/",
"https://server:port/path-segment",
"https://server:port/path-segment/",
// Things that are close to disallowed path segments
"https://server:port/...",
"https://server:port/.../",
"https://server:port/path-segment/...",
"https://server:port/path-segment/path.",
"https://server:port/path-segment/path./",
// Double slashes
"https://server:port/path-segment//path",
// Queries
"http://server/path?",
"http://server/path?query",
"http://server/path?query=value",
// Empty fragments
"http://server/path?query=value#",
}
for i, u := range allowed {
ok, msg := ValidateRedirectURI(u)
if !ok {
t.Errorf("%d expected %q to be allowed, but got error message %q", i, u, msg)
}
}
disallowed := []string{
// invalid URL
"://server:port/",
// . or .. segments
"http://server/.",
"http://server/./",
"http://server/..",
"http://server/../",
"http://server/path/..",
"http://server/path/../",
"http://server/path/../path",
// Fragments
"http://server/path?query#test",
}
for i, u := range disallowed {
ok, _ := ValidateRedirectURI(u)
if ok {
t.Errorf("%d expected %q to be disallowed", i, u)
}
}
}
func TestValidateClientAuthorization(t *testing.T) {
errs := ValidateClientAuthorization(&oapi.OAuthClientAuthorization{
ObjectMeta: api.ObjectMeta{Name: "myusername:myclientname"},
ClientName: "myclientname",
UserName: "myusername",
UserUID: "myuseruid",
})
if len(errs) != 0 {
t.Errorf("expected success: %v", errs)
}
errorCases := map[string]struct {
A oapi.OAuthClientAuthorization
T field.ErrorType
F string
}{
"zero-length name": {
A: oapi.OAuthClientAuthorization{
ClientName: "myclientname",
UserName: "myusername",
UserUID: "myuseruid",
},
T: field.ErrorTypeRequired,
F: "metadata.name",
},
"invalid name": {
A: oapi.OAuthClientAuthorization{
ObjectMeta: api.ObjectMeta{Name: "anotheruser:anotherclient"},
ClientName: "myclientname",
UserName: "myusername",
UserUID: "myuseruid",
},
T: field.ErrorTypeInvalid,
F: "metadata.name",
},
"disallowed namespace": {
A: oapi.OAuthClientAuthorization{
ObjectMeta: api.ObjectMeta{Name: "myusername:myclientname", Namespace: "foo"},
ClientName: "myclientname",
UserName: "myusername",
UserUID: "myuseruid",
},
T: field.ErrorTypeForbidden,
F: "metadata.namespace",
},
"no scope handler": {
A: oapi.OAuthClientAuthorization{
ObjectMeta: api.ObjectMeta{Name: "myusername:myclientname"},
ClientName: "myclientname",
UserName: "myusername",
UserUID: "myuseruid",
Scopes: []string{"invalid"},
},
T: field.ErrorTypeInvalid,
F: "scopes[0]",
},
"bad scope": {
A: oapi.OAuthClientAuthorization{
ObjectMeta: api.ObjectMeta{Name: "myusername:myclientname"},
ClientName: "myclientname",
UserName: "myusername",
UserUID: "myuseruid",
Scopes: []string{"user:dne"},
},
T: field.ErrorTypeInvalid,
F: "scopes[0]",
},
}
for k, v := range errorCases {
errs := ValidateClientAuthorization(&v.A)
if len(errs) == 0 {
t.Errorf("expected failure %s for %v", k, v.A)
continue
}
for i := range errs {
if errs[i].Type != v.T {
t.Errorf("%s: expected errors to have type %s GOT: %v", k, v.T, errs[i])
}
if errs[i].Field != v.F {
t.Errorf("%s: expected errors to have field %s GOT: %v", k, v.F, errs[i])
}
}
}
}
func TestValidateClient(t *testing.T) {
errs := ValidateClient(&oapi.OAuthClient{
ObjectMeta: api.ObjectMeta{Name: "client-name"},
})
if len(errs) != 0 {
t.Errorf("expected success: %v", errs)
}
errorCases := map[string]struct {
Client oapi.OAuthClient
T field.ErrorType
F string
}{
"zero-length name": {
Client: oapi.OAuthClient{},
T: field.ErrorTypeRequired,
F: "metadata.name",
},
"disallowed namespace": {
Client: oapi.OAuthClient{ObjectMeta: api.ObjectMeta{Name: "name", Namespace: "foo"}},
T: field.ErrorTypeForbidden,
F: "metadata.namespace",
},
"literal must have value": {
Client: oapi.OAuthClient{
ObjectMeta: api.ObjectMeta{Name: "client-name"},
ScopeRestrictions: []oapi.ScopeRestriction{{ExactValues: []string{""}}},
},
T: field.ErrorTypeInvalid,
F: "scopeRestrictions[0].literals[0]",
},
"must have role names": {
Client: oapi.OAuthClient{
ObjectMeta: api.ObjectMeta{Name: "client-name"},
ScopeRestrictions: []oapi.ScopeRestriction{
{
ClusterRole: &oapi.ClusterRoleScopeRestriction{Namespaces: []string{"b"}},
},
},
},
T: field.ErrorTypeRequired,
F: "scopeRestrictions[0].clusterRole.roleNames",
},
"must have namespaces": {
Client: oapi.OAuthClient{
ObjectMeta: api.ObjectMeta{Name: "client-name"},
ScopeRestrictions: []oapi.ScopeRestriction{
{
ClusterRole: &oapi.ClusterRoleScopeRestriction{RoleNames: []string{"a"}},
},
},
},
T: field.ErrorTypeRequired,
F: "scopeRestrictions[0].clusterRole.namespaces",
},
}
for k, v := range errorCases {
errs := ValidateClient(&v.Client)
if len(errs) == 0 {
t.Errorf("expected failure %s for %v", k, v.Client)
continue
}
for i := range errs {
if errs[i].Type != v.T {
t.Errorf("%s: expected errors to have type %s: %v", k, v.T, errs[i])
}
if errs[i].Field != v.F {
t.Errorf("%s: expected errors to have field %s: %v", k, v.F, errs[i])
}
}
}
}
func TestValidateAccessTokens(t *testing.T) {
errs := ValidateAccessToken(&oapi.OAuthAccessToken{
ObjectMeta: api.ObjectMeta{Name: "accessTokenNameWithMinimumLength"},
ClientName: "myclient",
UserName: "myusername",
UserUID: "myuseruid",
})
if len(errs) != 0 {
t.Errorf("expected success: %v", errs)
}
errorCases := map[string]struct {
Token oapi.OAuthAccessToken
T field.ErrorType
F string
}{
"zero-length name": {
Token: oapi.OAuthAccessToken{
ClientName: "myclient",
UserName: "myusername",
UserUID: "myuseruid",
},
T: field.ErrorTypeRequired,
F: "metadata.name",
},
"disallowed namespace": {
Token: oapi.OAuthAccessToken{
ObjectMeta: api.ObjectMeta{Name: "accessTokenNameWithMinimumLength", Namespace: "foo"},
ClientName: "myclient",
UserName: "myusername",
UserUID: "myuseruid",
},
T: field.ErrorTypeForbidden,
F: "metadata.namespace",
},
"no scope handler": {
Token: oapi.OAuthAccessToken{
ObjectMeta: api.ObjectMeta{Name: "accessTokenNameWithMinimumLength"},
ClientName: "myclient",
UserName: "myusername",
UserUID: "myuseruid",
Scopes: []string{"invalid"},
},
T: field.ErrorTypeInvalid,
F: "scopes[0]",
},
"bad scope": {
Token: oapi.OAuthAccessToken{
ObjectMeta: api.ObjectMeta{Name: "accessTokenNameWithMinimumLength"},
ClientName: "myclient",
UserName: "myusername",
UserUID: "myuseruid",
Scopes: []string{"user:dne"},
},
T: field.ErrorTypeInvalid,
F: "scopes[0]",
},
}
for k, v := range errorCases {
errs := ValidateAccessToken(&v.Token)
if len(errs) == 0 {
t.Errorf("expected failure %s for %v", k, v.Token)
continue
}
for i := range errs {
if errs[i].Type != v.T {
t.Errorf("%s: expected errors to have type %s: %v", k, v.T, errs[i])
}
if errs[i].Field != v.F {
t.Errorf("%s: expected errors to have field %s: %v", k, v.F, errs[i])
}
}
}
}
func TestValidateAuthorizeTokens(t *testing.T) {
errs := ValidateAuthorizeToken(&oapi.OAuthAuthorizeToken{
ObjectMeta: api.ObjectMeta{Name: "authorizeTokenNameWithMinimumLength"},
ClientName: "myclient",
UserName: "myusername",
UserUID: "myuseruid",
Scopes: []string{`user:info`},
})
if len(errs) != 0 {
t.Errorf("expected success: %v", errs)
}
errorCases := map[string]struct {
Token oapi.OAuthAuthorizeToken
T field.ErrorType
F string
}{
"zero-length name": {
Token: oapi.OAuthAuthorizeToken{
ClientName: "myclient",
UserName: "myusername",
UserUID: "myuseruid",
},
T: field.ErrorTypeRequired,
F: "metadata.name",
},
"zero-length client name": {
Token: oapi.OAuthAuthorizeToken{
ObjectMeta: api.ObjectMeta{Name: "authorizeTokenNameWithMinimumLength"},
UserName: "myusername",
UserUID: "myuseruid",
},
T: field.ErrorTypeRequired,
F: "clientName",
},
"zero-length user name": {
Token: oapi.OAuthAuthorizeToken{
ObjectMeta: api.ObjectMeta{Name: "authorizeTokenNameWithMinimumLength"},
ClientName: "myclient",
UserUID: "myuseruid",
},
T: field.ErrorTypeRequired,
F: "userName",
},
"zero-length user uid": {
Token: oapi.OAuthAuthorizeToken{
ObjectMeta: api.ObjectMeta{Name: "authorizeTokenNameWithMinimumLength"},
ClientName: "myclient",
UserName: "myusername",
},
T: field.ErrorTypeRequired,
F: "userUID",
},
"disallowed namespace": {
Token: oapi.OAuthAuthorizeToken{
ObjectMeta: api.ObjectMeta{Name: "authorizeTokenNameWithMinimumLength", Namespace: "foo"},
ClientName: "myclient",
UserName: "myusername",
UserUID: "myuseruid",
},
T: field.ErrorTypeForbidden,
F: "metadata.namespace",
},
"no scope handler": {
Token: oapi.OAuthAuthorizeToken{
ObjectMeta: api.ObjectMeta{Name: "authorizeTokenNameWithMinimumLength"},
ClientName: "myclient",
UserName: "myusername",
UserUID: "myuseruid",
Scopes: []string{"invalid"},
},
T: field.ErrorTypeInvalid,
F: "scopes[0]",
},
"bad scope": {
Token: oapi.OAuthAuthorizeToken{
ObjectMeta: api.ObjectMeta{Name: "authorizeTokenNameWithMinimumLength"},
ClientName: "myclient",
UserName: "myusername",
UserUID: "myuseruid",
Scopes: []string{"user:dne"},
},
T: field.ErrorTypeInvalid,
F: "scopes[0]",
},
"illegal character": {
Token: oapi.OAuthAuthorizeToken{
ObjectMeta: api.ObjectMeta{Name: "authorizeTokenNameWithMinimumLength"},
ClientName: "myclient",
UserName: "myusername",
UserUID: "myuseruid",
Scopes: []string{`role:asdf":foo`},
},
T: field.ErrorTypeInvalid,
F: "scopes[0]",
},
}
for k, v := range errorCases {
errs := ValidateAuthorizeToken(&v.Token)
if len(errs) == 0 {
t.Errorf("expected failure %s for %v", k, v.Token)
continue
}
for i := range errs {
if errs[i].Type != v.T {
t.Errorf("%s: expected errors to have type %s: %v", k, v.T, errs[i])
}
if errs[i].Field != v.F {
t.Errorf("%s: expected errors to have field %s: %v", k, v.F, errs[i])
}
}
}
}
func TestValidateAccessTokensUpdate(t *testing.T) {
valid := &oapi.OAuthAccessToken{
ObjectMeta: api.ObjectMeta{Name: "accessTokenNameWithMinimumLength", ResourceVersion: "1"},
ClientName: "myclient",
UserName: "myusername",
UserUID: "myuseruid",
}
errs := ValidateAccessTokenUpdate(valid, valid)
if len(errs) != 0 {
t.Errorf("expected success: %v", errs)
}
errorCases := map[string]struct {
Token oapi.OAuthAccessToken
Change func(*oapi.OAuthAccessToken)
T field.ErrorType
F string
}{
"change name": {
Token: *valid,
Change: func(obj *oapi.OAuthAccessToken) {
obj.Name = ""
},
T: field.ErrorTypeInvalid,
F: "metadata.name",
},
"change userName": {
Token: *valid,
Change: func(obj *oapi.OAuthAccessToken) {
obj.UserName = ""
},
T: field.ErrorTypeInvalid,
F: "[]",
},
}
for k, v := range errorCases {
copied, _ := api.Scheme.Copy(&v.Token)
newToken := copied.(*oapi.OAuthAccessToken)
v.Change(newToken)
errs := ValidateAccessTokenUpdate(newToken, &v.Token)
if len(errs) == 0 {
t.Errorf("expected failure %s for %v", k, v.Token)
continue
}
for i := range errs {
if errs[i].Type != v.T {
t.Errorf("%s: expected errors to have type %s: %v", k, v.T, errs[i])
}
if errs[i].Field != v.F {
t.Errorf("%s: expected errors to have field %s: %v", k, v.F, errs[i])
}
}
}
}
func TestValidateAuthorizeTokensUpdate(t *testing.T) {
valid := &oapi.OAuthAuthorizeToken{
ObjectMeta: api.ObjectMeta{Name: "authorizeTokenNameWithMinimumLength", ResourceVersion: "1"},
ClientName: "myclient",
UserName: "myusername",
UserUID: "myuseruid",
Scopes: []string{`user:info`},
}
errs := ValidateAuthorizeTokenUpdate(valid, valid)
if len(errs) != 0 {
t.Errorf("expected success: %v", errs)
}
errorCases := map[string]struct {
Token oapi.OAuthAuthorizeToken
Change func(*oapi.OAuthAuthorizeToken)
T field.ErrorType
F string
}{
"change name": {
Token: *valid,
Change: func(obj *oapi.OAuthAuthorizeToken) {
obj.Name = ""
},
T: field.ErrorTypeInvalid,
F: "metadata.name",
},
"change userUID": {
Token: *valid,
Change: func(obj *oapi.OAuthAuthorizeToken) {
obj.UserUID = ""
},
T: field.ErrorTypeInvalid,
F: "[]",
},
}
for k, v := range errorCases {
copied, _ := api.Scheme.Copy(&v.Token)
newToken := copied.(*oapi.OAuthAuthorizeToken)
v.Change(newToken)
errs := ValidateAuthorizeTokenUpdate(newToken, &v.Token)
if len(errs) == 0 {
t.Errorf("expected failure %s for %v", k, v.Token)
continue
}
for i := range errs {
if errs[i].Type != v.T {
t.Errorf("%s: expected errors to have type %s: %v", k, v.T, errs[i])
}
if errs[i].Field != v.F {
t.Errorf("%s: expected errors to have field %s: %v", k, v.F, errs[i])
}
}
}
}