Skip to content

Commit

Permalink
Merge pull request #1450 from liggitt/split_identity
Browse files Browse the repository at this point in the history
Merged by openshift-bot
  • Loading branch information
OpenShift Bot committed Mar 30, 2015
2 parents 5c50537 + 1919eda commit ca554b7
Show file tree
Hide file tree
Showing 64 changed files with 3,093 additions and 863 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions examples/sample-app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,9 @@ This section covers how to perform all the steps of building, deploying, and upd
$ export CURL_CA_BUNDLE=`pwd`/openshift.local.certificates/ca/cert.crt
$ sudo chmod +r "$KUBECONFIG"

4. Bind a user to the `view` role in the default namespace so you can observe progress in the web console (`anypassword` is an identity provider, `test-admin` is username)
4. Bind a user names `test-admin` to the `view` role in the default namespace so you can observe progress in the web console

$ openshift ex policy add-role-to-user view anypassword:test-admin
$ openshift ex policy add-role-to-user view test-admin

5. *Optional:* View the OpenShift web console in your browser by browsing to `https://<host>:8443/console`. Login using the user `test-admin` and any password.

Expand Down Expand Up @@ -186,7 +186,7 @@ This section covers how to perform all the steps of building, deploying, and upd

9. Create a new project in OpenShift. This creates a namespace `test` to contain the builds and app that we will generate below.

$ openshift ex new-project test --display-name="OpenShift 3 Sample" --description="This is an example project to demonstrate OpenShift v3" --admin=anypassword:test-admin
$ openshift ex new-project test --display-name="OpenShift 3 Sample" --description="This is an example project to demonstrate OpenShift v3" --admin=test-admin

10. *Optional:* View the OpenShift web console in your browser by browsing to `https://<host>:8443/console`. Login using the user `test-admin` and any password.

Expand Down
10 changes: 5 additions & 5 deletions hack/test-cmd.sh
Original file line number Diff line number Diff line change
Expand Up @@ -325,8 +325,8 @@ echo "ex policy: ok"

# Test the commands the UI projects page tells users to run
# These should match what is described in projects.html
osadm new-project ui-test-project --admin="anypassword:createuser"
osadm policy add-role-to-user admin anypassword:adduser -n ui-test-project
osadm new-project ui-test-project --admin="createuser"
osadm policy add-role-to-user admin adduser -n ui-test-project
# Make sure project can be listed by osc (after auth cache syncs)
sleep 2 && [ "$(osc get projects | grep 'ui-test-project')" ]
# Make sure users got added
Expand All @@ -335,10 +335,10 @@ sleep 2 && [ "$(osc get projects | grep 'ui-test-project')" ]
echo "ui-project-commands: ok"

# Test deleting and recreating a project
osadm new-project recreated-project --admin="anypassword:createuser1"
osadm new-project recreated-project --admin="createuser1"
osc delete project recreated-project
osadm new-project recreated-project --admin="anypassword:createuser2"
osc describe policybinding master -n recreated-project | grep anypassword:createuser2
osadm new-project recreated-project --admin="createuser2"
osc describe policybinding master -n recreated-project | grep createuser2
echo "ex new-project: ok"

# Test running a router
Expand Down
4 changes: 2 additions & 2 deletions hack/test-end-to-end.sh
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,10 @@ wait_for_url "${API_SCHEME}://${API_HOST}:${API_PORT}/api/v1beta1/minions/127.0.
export KUBERNETES_MASTER="${API_SCHEME}://${API_HOST}:${API_PORT}"

# add e2e-user as a viewer for the default namespace so we can see infrastructure pieces appear
openshift ex policy add-role-to-user view anypassword:e2e-user --namespace=default
openshift ex policy add-role-to-user view e2e-user --namespace=default

# create test project so that this shows up in the console
openshift ex new-project test --description="This is an example project to demonstrate OpenShift v3" --admin="anypassword:e2e-user"
openshift ex new-project test --description="This is an example project to demonstrate OpenShift v3" --admin="e2e-user"

echo "The console should be available at ${API_SCHEME}://${PUBLIC_MASTER_HOST}:$(($API_PORT + 1)). You may need to visit ${API_SCHEME}://${PUBLIC_MASTER_HOST}:${API_PORT} first to accept the certificate."
echo "Log in as 'e2e-user' to see the 'test' project."
Expand Down
2 changes: 1 addition & 1 deletion pkg/api/latest/latest.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ var originTypes = []string{
"Template", "TemplateConfig",
"Route",
"Project",
"User", "UserIdentityMapping",
"User", "Identity", "UserIdentityMapping",
"OAuthClient", "OAuthClientAuthorization", "OAuthAccessToken", "OAuthAuthorizeToken",
"Role", "RoleBinding", "Policy", "PolicyBinding", "ResourceAccessReview", "SubjectAccessReview",
}
Expand Down
42 changes: 30 additions & 12 deletions pkg/auth/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,26 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/user"
)

const (
// IdentityDisplayNameKey is the key for an optional display name in an identity's Extra map
IdentityDisplayNameKey = "name"
// IdentityEmailKey is the key for an optional email address in an identity's Extra map
IdentityEmailKey = "email"
// IdentityLoginKey is the key for an optional login in an identity's Extra map.
// This is useful when the immutable providerUserName is different than the login used to authenticate
// If present, this extra value is used as the preferred username
IdentityLoginKey = "login"
)

// UserIdentityInfo contains information about an identity. Identities are distinct from users. An authentication server of
// some kind (like oauth for example) describes an identity. Our system controls the users mapped to this identity.
type UserIdentityInfo interface {
// GetUserName uniquely identifies this particular identity for this provider. It is NOT guaranteed to be unique across providers
GetUserName() string
// GetIdentityName returns the name of this identity. It must be equal to GetProviderName() + ":" + GetProviderUserName()
GetIdentityName() string
// GetProviderName returns the name of the provider of this identity.
GetProviderName() string
// GetProviderUserName uniquely identifies this particular identity for this provider. It is NOT guaranteed to be unique across providers
GetProviderUserName() string
// GetExtra is a map to allow providers to add additional fields that they understand
GetExtra() map[string]string
}
Expand All @@ -37,27 +50,32 @@ type Grant struct {
}

type DefaultUserIdentityInfo struct {
UserName string
ProviderName string
Extra map[string]string
ProviderName string
ProviderUserName string
Extra map[string]string
}

// NewDefaultUserIdentityInfo returns a DefaultUserIdentity info with a non-nil Extra component
func NewDefaultUserIdentityInfo(username string) DefaultUserIdentityInfo {
return DefaultUserIdentityInfo{
UserName: username,
Extra: make(map[string]string),
// NewDefaultUserIdentityInfo returns a DefaultUserIdentityInfo with a non-nil Extra component
func NewDefaultUserIdentityInfo(providerName, providerUserName string) *DefaultUserIdentityInfo {
return &DefaultUserIdentityInfo{
ProviderName: providerName,
ProviderUserName: providerUserName,
Extra: map[string]string{},
}
}

func (i *DefaultUserIdentityInfo) GetUserName() string {
return i.UserName
func (i *DefaultUserIdentityInfo) GetIdentityName() string {
return i.ProviderName + ":" + i.ProviderUserName
}

func (i *DefaultUserIdentityInfo) GetProviderName() string {
return i.ProviderName
}

func (i *DefaultUserIdentityInfo) GetProviderUserName() string {
return i.ProviderUserName
}

func (i *DefaultUserIdentityInfo) GetExtra() map[string]string {
return i.Extra
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ import (

// alwaysAcceptPasswordAuthenticator approves any login attempt with non-blank username and password
type alwaysAcceptPasswordAuthenticator struct {
providerName string
identityMapper authapi.UserIdentityMapper
}

// New creates a new password authenticator that approves any login attempt with non-blank username and password
func New(identityMapper authapi.UserIdentityMapper) authenticator.Password {
return &alwaysAcceptPasswordAuthenticator{identityMapper}
func New(providerName string, identityMapper authapi.UserIdentityMapper) authenticator.Password {
return &alwaysAcceptPasswordAuthenticator{providerName, identityMapper}
}

// AuthenticatePassword approves any login attempt with non-blank username and password
Expand All @@ -26,9 +27,7 @@ func (a alwaysAcceptPasswordAuthenticator) AuthenticatePassword(username, passwo
return nil, false, nil
}

identity := &authapi.DefaultUserIdentityInfo{
UserName: username,
}
identity := authapi.NewDefaultUserIdentityInfo(a.providerName, username)
user, err := a.identityMapper.UserFor(identity)
glog.V(4).Infof("Got userIdentityMapping: %#v", user)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,22 @@ import (
// A successful response may also include name and/or email:
// {"id":"userid", "name": "User Name", "email":"user@example.com"}
type Authenticator struct {
url string
mapper authapi.UserIdentityMapper
providerName string
url string
mapper authapi.UserIdentityMapper
}

// RemoteUserData holds user data returned from a remote basic-auth protected endpoint.
// These field names can not be changed unless external integrators are also updated.
type RemoteUserData struct {
ID string
Name string
// ID is the immutable identity of the user
ID string
// Login is the optional login of the user
// Useful when the id is different than the username/login used by the user to authenticate
Login string
// Name is the optional display name of the user
Name string
// Email is the optional email address of the user
Email string
}

Expand All @@ -42,8 +49,8 @@ type RemoteError struct {
}

// New returns an authenticator which will make a basic auth call to the given url.
func New(url string, mapper authapi.UserIdentityMapper) authenticator.Password {
return &Authenticator{url, mapper}
func New(providerName string, url string, mapper authapi.UserIdentityMapper) authenticator.Password {
return &Authenticator{providerName, url, mapper}
}

func (a *Authenticator) AuthenticatePassword(username, password string) (user.Info, bool, error) {
Expand Down Expand Up @@ -89,13 +96,10 @@ func (a *Authenticator) AuthenticatePassword(username, password string) (user.In
return nil, false, errors.New("Could not retrieve user data")
}

identity := &authapi.DefaultUserIdentityInfo{
UserName: username,
Extra: map[string]string{
"name": remoteUserData.Name,
"email": remoteUserData.Email,
},
}
identity := authapi.NewDefaultUserIdentityInfo(a.providerName, remoteUserData.ID)
identity.Extra[authapi.IdentityDisplayNameKey] = remoteUserData.Name
identity.Extra[authapi.IdentityLoginKey] = remoteUserData.Login
identity.Extra[authapi.IdentityEmailKey] = remoteUserData.Email
user, err := a.mapper.UserFor(identity)
glog.V(4).Infof("Got userIdentityMapping: %#v", user)
if err != nil {
Expand Down
20 changes: 10 additions & 10 deletions pkg/auth/authenticator/password/htpasswd/htpasswd.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,19 @@ import (

// Authenticator watches a file generated by htpasswd to validate usernames and passwords
type Authenticator struct {
file string
fileInfo os.FileInfo
mapper authapi.UserIdentityMapper
usernames map[string]string
providerName string
file string
fileInfo os.FileInfo
mapper authapi.UserIdentityMapper
usernames map[string]string
}

// New returns an authenticator which will validate usernames and passwords against the given htpasswd file
func New(file string, mapper authapi.UserIdentityMapper) (authenticator.Password, error) {
func New(providerName string, file string, mapper authapi.UserIdentityMapper) (authenticator.Password, error) {
auth := &Authenticator{
file: file,
mapper: mapper,
providerName: providerName,
file: file,
mapper: mapper,
}
if err := auth.loadIfNeeded(); err != nil {
return nil, err
Expand All @@ -52,9 +54,7 @@ func (a *Authenticator) AuthenticatePassword(username, password string) (user.In
return nil, false, err
}

identity := &authapi.DefaultUserIdentityInfo{
UserName: username,
}
identity := authapi.NewDefaultUserIdentityInfo(a.providerName, username)
user, err := a.mapper.UserFor(identity)
glog.V(4).Infof("Got userIdentityMapping: %#v", user)
if err != nil {
Expand Down
15 changes: 7 additions & 8 deletions pkg/auth/authenticator/password/oauthpassword/oauthpassword.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ import (
)

type Authenticator struct {
mapper authapi.UserIdentityMapper
client *osincli.Client
providerName string
mapper authapi.UserIdentityMapper
client *osincli.Client
}

func New(client *osincli.Client, identityMapper authapi.UserIdentityMapper) authenticator.Password {
return &Authenticator{identityMapper, client}
func New(providerName string, client *osincli.Client, identityMapper authapi.UserIdentityMapper) authenticator.Password {
return &Authenticator{providerName, identityMapper, client}
}

func (a *Authenticator) AuthenticatePassword(username, password string) (user.Info, bool, error) {
Expand All @@ -33,10 +34,8 @@ func (a *Authenticator) AuthenticatePassword(username, password string) (user.In
return nil, false, err
}

identity := &authapi.DefaultUserIdentityInfo{
UserName: username,
Extra: map[string]string{"token": token.AccessToken},
}
identity := authapi.NewDefaultUserIdentityInfo(a.providerName, username)
identity.Extra["token"] = token.AccessToken
user, err := a.mapper.UserFor(identity)
glog.V(4).Infof("Got userIdentityMapping: %#v", user)
if err != nil {
Expand Down
13 changes: 6 additions & 7 deletions pkg/auth/authenticator/request/headerrequest/requestheader.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ func NewDefaultConfig() *Config {
}

type Authenticator struct {
config *Config
mapper authapi.UserIdentityMapper
providerName string
config *Config
mapper authapi.UserIdentityMapper
}

func NewAuthenticator(config *Config, mapper authapi.UserIdentityMapper) *Authenticator {
return &Authenticator{config, mapper}
func NewAuthenticator(providerName string, config *Config, mapper authapi.UserIdentityMapper) *Authenticator {
return &Authenticator{providerName, config, mapper}
}

func (a *Authenticator) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
Expand All @@ -46,9 +47,7 @@ func (a *Authenticator) AuthenticateRequest(req *http.Request) (user.Info, bool,
return nil, false, nil
}

identity := &authapi.DefaultUserIdentityInfo{
UserName: username,
}
identity := authapi.NewDefaultUserIdentityInfo(a.providerName, username)
user, err := a.mapper.UserFor(identity)
if err != nil {
return nil, false, err
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
type TestUserIdentityMapper struct{}

func (m *TestUserIdentityMapper) UserFor(identityInfo api.UserIdentityInfo) (user.Info, error) {
return &user.DefaultInfo{Name: identityInfo.GetUserName()}, nil
return &user.DefaultInfo{Name: identityInfo.GetProviderUserName()}, nil
}

func TestRequestHeader(t *testing.T) {
Expand Down Expand Up @@ -61,7 +61,7 @@ func TestRequestHeader(t *testing.T) {

for k, testcase := range testcases {
mapper := &TestUserIdentityMapper{}
auth := NewAuthenticator(&Config{testcase.ConfiguredHeaders}, mapper)
auth := NewAuthenticator("testprovider", &Config{testcase.ConfiguredHeaders}, mapper)
req := &http.Request{Header: testcase.RequestHeaders}

user, ok, err := auth.AuthenticateRequest(req)
Expand Down
Loading

0 comments on commit ca554b7

Please sign in to comment.