Documentation ¶
Overview ¶
Affinity provides user grouping and role-based access controls (RBAC) for any identity provider that defines a small set of authentication primitives.
The examples documented here illustrate basic API usage with a very simple hypothetical message board.
For a more complete example, reference the unit tests, and the source files in package github.com/juju/affinity/group package, where Affinity uses its own RBAC to control access to user-group administration.
github.com/juju/affinity/server exposes an HTTP API over the group service. The command-line interface in cmd/ is a utility to launch the service and connect to it, using Ubuntu SSO as an identity provider.
Use the following types for working with identity and RBAC in Affinity.
Principal ¶
A Principal is a singular User or a corporate Group (a collection of users or subgroups) which can be granted a Role over a Resource.
User ¶
Users are unique individual accounts which can provide a proof of identity. A user is identified by a Scheme and an Id string. The Id string must be unique within the scope of the Scheme.
A User can be a member of a Group. A User also can be treated as a Principal. The canonical string representation of a user identity in affinity is "SchemeName:UserId".
Scheme ¶
A Scheme provides two important functions in affinity:
1. Authenticating a user and generating a proof of identity ownership.
2. Validating that a proof of identity belongs to a given User.
These functions are intended to be adaptable to OAuth, OpenID, SASL and other token-based authentication mechanisms. The Ubuntu Single-Sign On (SSO) provider is a reference example.
Schemes are registered to unique namespaces. This namespace comprises the "SchemeName" component of a canonical User string representation.
Group ¶
A group is a collection of Users or sub-Groups with a unique name. Groups should be defined by a common association, rather than by capability you want the members to have with a resource.
In other words, don't group users to define permissions on resources. Grant common, reusable permissions on resources to users and groups.
It is worth mentioning that some Schemes might support their own concept of user groups. For example, a Launchpad Scheme could access team membership, and a Github Scheme could access Organization membership. Proxying these external groups in Affinity may be supported in future releases.
Permission ¶
Permissions are fine-grained capabilities or actions which take place in an application. Affinity provides a means to look up whether a given principal has a permission to act on a certain resource. Each permission is given a name identifier unique to the application capability it represents.
Let your application define your permissions. For example, if you were writing a filesystem, you might have permissions defined like: read-file, execute-file, write-file, read-directory, write-directory, etc.
Role ¶
Roles are a higher-level definition of capabilities. Essentially a Role is a bundle of permissions given a name. Roles should be defined by the "types of access" you wish to grant users and groups on your application's resources.
For example, someone in a Pilot role should have permissions like 'board', 'enter-cabin', 'move-cockpit-controls' on an "airplane" resource. A Passenger role should be able to 'board', but not 'enter-cabin' or 'move-cockpit-controls'.
Resource ¶
A resource is the object to which access is granted. In Affinity, a Resource is declared by a URI, which will have meaning to the application implementating RBAC.
Resources also declare the full set of permissions they support. That way, you can't make absurd role grants that don't make sense for the resource object of the grant.
Resources do not currently support the concept of hierarchy in Affinity -- they are all flat, and in essence just canonical names to be matched in an access control query.
Store ¶
Affinity stores user groupings and role grants in persistent storage. The Store interface defines lower-level primitives which are implemented for different providers, such as MongoDB, in-memory, or others.
Access ¶
Use Access to connect to storage and check access permissions for a given user/group on a resource.
Admin ¶
Admin extends Access with the capability to grant and revoke user or group roles on resources. Role grants in Affinity are "positive" and additive in nature. Granting a role will cause a permission lookup for the user/group on a resource to match if any granted role contains that permission.
Revoking a role will remove this relationship, so that the lookup no longer matches and access is denied.
It is important to note that when it comes to role grants on groups, there is no way to revoke a role's transitive permissions from a group member. All members of the group will receive the role permission, or none of them will.
Index ¶
Constants ¶
const AnyId = "*"
AnyId is a wildcard match for any valid, authenticated identifier.
Variables ¶
Functions ¶
This section is empty.
Types ¶
type Group ¶
Group defines a corporate principal identity composed of zero or more principal members.
type HandshakeScheme ¶
type HandshakeScheme interface { Scheme // SignIn redirects to an identity provider, such as an OpenID or OAuth service. // This interaction requires the client to be a web browser in most cases. SignIn(w http.ResponseWriter, r *http.Request) (err error) // Authenticated handles a redirect to an application "callback" endpoint from the // identity provider. Implementations will typically create a session here for the // established identity. Authenticated(w http.ResponseWriter, r *http.Request) }
HandshakeScheme handles handshake identity protocols such as OpenID or OAuth 2 for HTTP services.
type Identity ¶
type Identity struct {
Scheme, Id string
}
Identity defines a principal identifier distinct within an authentication scheme.
type PasswordPrompter ¶
type PasswordPrompter struct{}
PasswordPrompter obtains a password for authentication by prompting for input on the current terminal device.
func (*PasswordPrompter) Password ¶
func (pp *PasswordPrompter) Password() (string, error)
type PasswordProvider ¶
type PasswordProvider interface { // Password obtains the password string and any error that occurred // in the process. Password() (string, error) }
PasswordProvider obtains a password for authentication providers that need one in order to generate an auth token.
type PasswordUnavailable ¶
type PasswordUnavailable struct{}
PasswordUnavilable is never able to obtain a password.
func (*PasswordUnavailable) Password ¶
func (pu *PasswordUnavailable) Password() (string, error)
type Principal ¶
type Principal interface { // String returns a string representation of the principal String() string // SchemeId returns the scheme and distinct identity of the principal SchemeId() (string, string) // Contains tests if a given user is contained by this one. // Functionally, Contains behaves according to the following rules: // A User contains itself and only itself. // A Group contains a given user if that user is a member, or contained by // some member of the group. Contains(member Principal) bool }
Principal defines a singular or corporate identity.
type Scheme ¶
type Scheme interface { // Name returns the locally bound name for this scheme. Name() string // Authenticate checks an HTTP request for a positive identity. // Returns the user identity if authentication is valid, otherwise // ErrUnauthorized as a prompt to authenticate. Authenticate(r *http.Request) (user User, err error) }
Scheme is a system which identifies principal user identities, and provides a means for those users to prove their identity.
type SchemeMap ¶
type SchemeMap struct {
// contains filtered or unexported fields
}
SchemeMap stores registered Scheme name-to-instance bindings.
func (*SchemeMap) Handshake ¶
func (sm *SchemeMap) Handshake(name string) HandshakeScheme
Handshake retrieves a handshake scheme by name, or nil.
func (*SchemeMap) HandshakeAll ¶
func (sm *SchemeMap) HandshakeAll() []HandshakeScheme
HandshakeAll retrieves all registered handshake schemes.
func (*SchemeMap) Register ¶
Register adds a scheme implementation to the map. A scheme can only be registered once. After that it cannot be replaced by another scheme.
func (*SchemeMap) Token ¶
func (sm *SchemeMap) Token(name string) TokenScheme
Token retrieves a token scheme by name, or nil.
type TokenInfo ¶
TokenInfo stores any RFC 2617 authorization token data, including custom provider tokens.
func NewTokenInfo ¶
NewTokenInfo creates a new TokenInfo instance.
func ParseTokenInfo ¶
ParseTokenInfo parses an RFC 2617 format authorization header.
type TokenScheme ¶
type TokenScheme interface { Scheme // Authorize creates an authorization token for the given identity. // Implementations may support multiple factors // (passphrases, private keys, etc.) when creating the authorization. Authorize(user User) (token *TokenInfo, err error) // Validate checks an authorization token created by Authorize. If valid, // returns the user identity for whom it was created. Validate(token *TokenInfo) (user User, err error) }
TokenScheme creates authorization tokens for identities and validates them.
type User ¶
type User struct {
Identity
}
User defines a singular, individual principal identity.
func AuthRequestToken ¶
func AuthRequestToken(scheme TokenScheme, r *http.Request) (User, error)
AuthRequestToken matches and validates RFC 2617 authorization headers as a principal user identity.