Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove principal + Allow updates to built-in users + Fix ccn/issues/66, ccn/issues/68 #44

Merged
merged 3 commits into from
Dec 14, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ func Authenticate(username, password string) (string, error) {

// generateToken generates JWT(JSON Web Token) with the given user principals
// params:
// principals: user principals
// principals: user principals; []string containing LDAP groups or username based on the authentication type(LDAP/Local)
// username: local or AD username of the user
// return values:
// `Token` string on successful creation of JWT otherwise any relevant error from the subsequent function
func generateToken(principals []*types.Principal, username string) (string, error) {
func generateToken(principals []string, username string) (string, error) {
log.Debugf("Generating token for user %q", username)

authZ, err := NewTokenWithClaims(principals) // create a new token with default `expiry` claim
Expand Down
14 changes: 6 additions & 8 deletions auth/ldap/ldap.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ type Manager struct {
// username: username to authenticate
// password: password of the user
// return values:
// []string: list of principals (LDAP group names that the user belongs)
// ErrLDAPConfigurationNotFound if the config is not found or as returned by ldapManager.Authenticate
func Authenticate(username, password string) ([]*types.Principal, error) {
func Authenticate(username, password string) ([]string, error) {
cfg, err := db.GetLdapConfiguration()
if err != nil {
return nil, err
Expand All @@ -77,9 +78,9 @@ func Authenticate(username, password string) ([]*types.Principal, error) {
// username: username to authenticate
// password: password of the user
// return values:
// []*types.Principal on successful authentication else nil
// []string containing LDAP group names of the user on successful authentication else nil
// error: nil on successful authentication otherwise ErrLDAPAccessDenied, ErrUserNotFound, etc.
func (lm *Manager) Authenticate(username, password string) ([]*types.Principal, error) {
func (lm *Manager) Authenticate(username, password string) ([]string, error) {
// list of attributes to be fetched from the matching records
var attributes = []string{
"memberof",
Expand Down Expand Up @@ -132,13 +133,10 @@ func (lm *Manager) Authenticate(username, password string) ([]*types.Principal,
return nil, err
}

// XXX: this code is not complete yet
// TODO: these groups should be associated with the principals

log.Debugf("Authorized groups:%#v", groups)

log.Info("AD authentication successful")
return nil, nil

return groups, nil
}

// getUserGroups performs a nested search on the given first-level user groups to uncover all the groups that the user is part of.
Expand Down
14 changes: 6 additions & 8 deletions auth/local/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
log "github.com/Sirupsen/logrus"
"github.com/contiv/ccn_proxy/common"
ccnerrors "github.com/contiv/ccn_proxy/common/errors"
"github.com/contiv/ccn_proxy/common/types"
"github.com/contiv/ccn_proxy/db"
)

Expand All @@ -13,9 +12,9 @@ import (
// username: username to authenticate
// password: password of the user
// return values:
// []*types.Principal on successful authentication else nil
// []string containing the `PrincipalName`(username) on successful authentication else nil
// error: nil on successful authentication otherwise ErrLocalAuthenticationFailed
func Authenticate(username, password string) ([]*types.Principal, error) {
func Authenticate(username, password string) ([]string, error) {
user, err := db.GetLocalUser(username)
if err != nil {
if err == ccnerrors.ErrKeyNotFound {
Expand All @@ -25,7 +24,7 @@ func Authenticate(username, password string) ([]*types.Principal, error) {
return nil, err
}

if user.LocalUser.Disable {
if user.Disable {
log.Debugf("Local user %q is disabled", username)
return nil, ccnerrors.ErrAccessDenied
}
Expand All @@ -35,8 +34,7 @@ func Authenticate(username, password string) ([]*types.Principal, error) {
return nil, ccnerrors.ErrAccessDenied
}

// TODO:this needs to be integrated with authZ module to fetch more principals based on the user role.
userPrincipals := []*types.Principal{}
userPrincipals = append(userPrincipals, &user.Principal)
return userPrincipals, nil
// local user's JWT will only contain the `username` + default claims (exp, role, etc.. )
// user.Username is the PrincipalName for localuser
return []string{user.Username}, nil
}
36 changes: 12 additions & 24 deletions auth/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,16 @@ func NewToken() *Token {
// return values:
// *Token: a token object encapsulating authorization claims
// error: nil if successful, else as returned by AddRoleClaim
func NewTokenWithClaims(principals []*types.Principal) (*Token, error) {
func NewTokenWithClaims(principals []string) (*Token, error) {
authZ := NewToken()

// add a claim for each principal
for _, principal := range principals {
if err := authZ.AddRoleClaim(principal); err != nil {
return nil, err
}
// NOTE: principal here is the group_name or username based on the authentication type(LDAP/Local)
authZ.AddClaim(principal, true)

authZ.AddRoleClaim(principal)
// TODO: Add role by iterating through the list of authorization for this principal
}

return authZ, nil
Expand All @@ -70,30 +72,16 @@ func NewTokenWithClaims(principals []*types.Principal) (*Token, error) {
// the user, hence an update is only performed if principal's role claim is
// higher than current value of role claim.
// params:
// principal: security principal associated with a user
// principal: principal(username/group_name) associated with a user
// return values:
// error: nil if successful, else relevant error if claim is malformed.
func (authZ *Token) AddRoleClaim(principal *types.Principal) error {
roleKey, err := GenerateClaimKey(principal.Role)
if err != nil {
return err
}
func (authZ *Token) AddRoleClaim(principal string) error {
// TODO: Iterate over the list of authz's of the given principal

val, found := authZ.tkn.Claims.(jwt.MapClaims)[roleKey] // this type casting is required due to jwt library changes
if found {
existingRole, err := types.Role(val.(string))
if err != nil {
return err
}

// principal's role is less privileged than what is stored, then return; otherwise update the token with new role
if principal.Role > existingRole { // highest role - Admin(0)
return nil
}
// FIXME: this is just to let the current systemtests PASS
if principal == types.Admin.String() || principal == types.Ops.String() {
authZ.AddClaim("role", principal)
}

// if the role is not part of claims, update the claim set with `Role`
authZ.AddClaim(roleKey, principal.Role.String())
return nil
}

Expand Down
51 changes: 9 additions & 42 deletions common/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,6 @@ const (
// Tenant is a type to represent the name of the tenant in CCN
type Tenant string

//
// Principal represents a 'user' to 'role' association. A 'user' can have many
// 'roles', and thus can have multiple principals representing it during a
// 'session'. This set is also known as the active role set (ARS).
//
// A CCN local user is a simplified version of this association, where the
// mapping is 1:1 - i.e., a CCN local user can have only one pre-defined role.
//
// A CCN ldap group (representing a LDAP group in some active directory forest)
// also has a 1:1 mapping with a principal. However, since a 'user' can be part
// of multiple ldap groups, the ARS will be determined at the time
// authentication is carried out, and may comprise of multiple principals.
//
// Fields:
// UUID: unique identifier of the principal
// Role: Role associated with a principal
//
type Principal struct {
UUID string `json:"uuid"`
Role RoleType `json:"roletype"`
}

// String returns the string representation of `RoleType`
func (role RoleType) String() string {
switch role {
Expand Down Expand Up @@ -77,30 +55,19 @@ func Role(roleStr string) (RoleType, error) {
//
// Fields:
// UserName: of the user. Read only field. Must be unique.
// FirstName: of the user
// LastName: of the user
// Password: of the user. Not stored anywhere. Used only for updates.
// Disable: if authorizations for this local user is disabled.
//
type LocalUser struct {
Username string `json:"username"`
Password string `json:"password"`
Disable bool `json:"disable"`
}

// InternalLocalUser information
//
// Fields:
// UserName: inherited from LocalUser
// Password: inherited from LocalUser. Not stored anywhere. Used to update password hash.
// Disble: inherited from LocalUser.
// Principal: associated principal object.
// PrincipalID: For each local user, there should be a principal created in the system.
// PasswordHash: of the password string.
//
type InternalLocalUser struct {
LocalUser
Principal Principal
PrincipalID string `json:"principal_id"`
PasswordHash []byte `json:"password_hash"`
type LocalUser struct {
Username string `json:"username"`
Password string `json:"password,omitempty"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Disable bool `json:"disable"`
PasswordHash []byte `json:"password_hash,omitempty"`
}

// LdapConfiguration represents the LDAP/AD configuration.
Expand Down
1 change: 0 additions & 1 deletion db/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
// various data store paths.
var (
RootLocalUsers = "local_users"
RootPrincipals = "principals"
RootLdapConfiguration = "ldap_configuration"
)

Expand Down
Loading