aah Security Design & Implementation

aah’s design goals are to simplify application security by being intuitive and easy to use. aah core design models how most people think about application security - in the context of someone (or something) interacting with an application.

Software applications are usually designed based on user stories. That is, you’ll often design user interfaces or service APIs based on how a user would (or should) interact with the software. For example, you might say, “If the user interacting with my application is logged in, I will show them a button they can click to view their account information. If they are not logged in, I will show a sign-up button.”

This example statement indicates that applications are largely written to satisfy user requirements and needs. Even if the ‘user’ is another software system and not a human being, you still write code to reflect behavior based on who (or what) is currently interacting with your software.

aah reflects these concepts in its own design. By matching what is already intuitive for software developers, aah remains intuitive and easy to use in practically any application.

aah security package/module is aahframe.work/security.

Design

At high level aah security implementations are all highly modular in design. It simplifies and enables flexible configuration with pluggability. The SecurityManager implementation does not do much at all. Instead, the SecurityManager implementations mostly act as a lightweight ‘container’, delegating almost all behavior to nested/wrapped components.

Components: SecurityManager, SessionManager, Subject

Interfaces: Schemer, Authenticator, PrincipalProvider, Authorizer, PasswordEncoder

SecurityManager

aah encourages a security.Subject-centric programming approach, most application developers will rarely, if ever, interact with the SecurityManager directly. Even so, it is still important to know how the SecurityManager functions.

SecurityManager implementations, this includes:

  • Authentication
  • Authorization
  • Session Management
  • Auth Scheme coordination
  • Subject creation
  • Logout

SessionManager

The SessionManager knows how to create and manage user Session lifecycles to provide a robust Session experience for users. The session.Storer interface provides an capability to use any backend of your choice for the session store. Out-of-the-box aah provides cookie and file store.

Subject

A security.Subject security-specific ‘view’ of the entity (user, 3rd-party service, cron job, etc) currently interacting with the application.

Schemer

The interface scheme.Schemer is a way to provides pluggable auth scheme for the application. You can configure one or more schemes and map it in the routes.conf per route basis also with default auth scheme if route doesn’t have specific.

Ready to use schemes are scheme.{FormAuth, BasicAuth, OAuth2Auth, GenericAuth} direct implementation of interface scheme.Schemer.

// Schemer interface is used to create Auth Scheme for aah.
type Schemer interface {
	// Init method gets called by aah during an application start.
	//
	// `keyName` is value of security auth scheme key.
	// 		For e.g.:
	// 			security.auth_schemes.<keyname>
	Init(appCfg *config.Config, keyName string) error

	// Key method returns auth scheme configuration KeyName.
	// For e.g: `security.auth_schemes.<keyname>`.
	Key() string

	// Scheme method returns auth scheme name. For e.g.: form, basic, oauth2, generic, etc.
	Scheme() string

	// DoAuthenticate method called by aah SecurityManager to get Subject authentication
	// information.
	DoAuthenticate(authcToken *authc.AuthenticationToken) (*authc.AuthenticationInfo, error)

	// DoAuthorizationInfo method called by aah SecurityManager to get
	// Subject's authorization information if successful authentication.
	DoAuthorizationInfo(authcInfo *authc.AuthenticationInfo) *authz.AuthorizationInfo

	// ExtractAuthenticationToken method called by aah SecurityManager to
	// extract identity details from the HTTP request.
	ExtractAuthenticationToken(r *ahttp.Request) *authc.AuthenticationToken
}

Authenticator

The interface authc.Authenticator is pluggable authentication info provider for the application.

// Authenticator interface is used to provide authentication information of application
// during a login.
type Authenticator interface {
	// Init method gets called by aah during an application start.
	Init(appCfg *config.Config) error

	// GetAuthenticationInfo method called by auth scheme to get subject's authentication
  // info for given authentication token.
	GetAuthenticationInfo(authcToken *authc.AuthenticationToken) (*authc.AuthenticationInfo, error)
}

PrincipalProvider

The interface authc.PrincipalProvider is pluggable Subject’s principals provider for third party authentication. For e.g.: OAuth2.

// PrincipalProvider interface is used to provide Subject's principals
// where authentication is done third party, for e.g. OAuth2, etc.
type PrincipalProvider interface {
	// Init method gets called by aah during an application start.
	Init(appCfg *config.Config) error

	// Principal method called by auth scheme to get Principals.
	//
	// 	For e.g: keyName is the auth scheme configuration KeyName.
	// 		 security.auth_schemes.<keyname>
	Principal(keyName string, v ess.Valuer) ([]*authc.Principal, error)
}

Authorizer

The interface authz.Authorizer is pluggable authorization info provider for Subject.

// Authorizer interface is used to provide authorization info (roles and permissions)
// after successful authentication.
type Authorizer interface {
	// Init method gets called by aah during an application start.
	Init(cfg *config.Config) error

	// GetAuthorizationInfo method called by auth scheme after authentication
  // successful to get Subject's (aka User) access control information
  // such as roles and permissions.
	GetAuthorizationInfo(authcInfo *authc.AuthenticationInfo) *authc.AuthorizationInfo
}

PasswordEncoder

The interface acrypto.PasswordEncoder is used to implement user password encoding such as bcrypt, scrypt, and pbkdf2.

// PasswordEncoder interface is used to encode and compare given hash and password
// based chosen hashing type. Such as `bcrypt`, `scrypt`, and `pbkdf2`.
//
// Caution: If you're using an unsecure hashing, your application is exposed to security
// issues. Consider using `bcrypt`, `scrypt`, or `pbkdf2`. Good read about
// hashing security - https://crackstation.net/hashing-security.htm
type PasswordEncoder interface {
	Compare(hash, password []byte) bool
}

Attribution

This documentation includes content from Shiro Security library and hapijs framework.