a guide to how "credentials" work in masks...
Credentials work together to do three things:
Every masked session can be configured to run through a number of credentials, executed in the order they’re specified in your configuration. In some cases, credentials can be composed to enable or disable different features.
Masks built-in credentials are designed to work together to support the common access control workflows, but custom credentials are easy to implement.
Here are some of the commonly used built-in types:
Session
checks actor
using the rails sessionNickname
checks actor
using a nickname supplied via paramsEmailAddress
checks actor
using an email address supplied via paramsPhoneNumber
checks actor
using a phone number supplied via paramsBearerToken
checks actor
using a bearer token sent via the Authorization headerPassword
checks password
using a password supplied via paramsDevice
checks device
using various signals from the sessionOneTimePassword
checks factor2
using a params-supplied codeBackupCode
checks factor2
using a params-supplied codeAll of the built-in types are namespaced under Masks::Credentials
. Check out
the API docs for information on each of them.
Credentials are simple Ruby classes that extend Masks::Credential
, so custom
credentials are easy to make. For example:
class MyCustomCredential < Masks::Credential
checks :custom
def lookup
# hook called when searching for an actor. This method
# should return an actor if it thinks it can find something
# based on the session context. (optional)
configuration.model(:actor).first if params[:custom]
end
def maskup
# hook called when an actor is available. should call
# approve! or deny! (or nothing) to verify the actor
# provided it exists. This affects only the "custom" check.
actor ? approve! : deny!
end
def backup
# final lifecycle hook, called once a decision has been
# made about the overall session (optional).
end
end
Once implemented, reference it in the appropriate mask(s) just like any other credential:
{
...
"credentials": [
"MyCustomCredential"
],
"checks": {
"custom": {
"lifetime": "P1D"
}
}
}
Take a look at the following examples illustrating how credentials are
referenced in masks.json
:
The mask for a hypothetical endpoint that exchanges a nickname/password for a session token would look similar to the following:
{
"request": {
"path": "/session",
"method": "POST"
},
"credentials": ["Session", "Email", "Nickname", "Password", "LastLogin"],
"checks": {
"actor": {
"lifetime": "P1D"
},
"password": {
"lifetime": "P1D"
}
}
}
The Session
, Email
, and Nickname
credentials work together to check the
actor
, while password
is checked by the Password
credential. If two-factor
authentication support is added then the various credentials for managing that
process would need to be added.
A simple mask to allow acting as an account without any real checks (useful, for example, during system tasks) would look like this:
{
"name": "my-task",
"credentials": ["Masquerade"],
"checks": {
"actor": {}
}
}
Then in Ruby, perhaps a command-line script:
Actor.find_each do |actor|
Masks.mask("my-task", as: actor) { |session| perform_system_task session }
end
Take a look at the page on access classes for examples on integrating them with custom credentials.
masks itself ships a masks.json
that is easy to read and extend. Take a look
at the source code to see how actual masks and credentials for login, signup,
password recovery, and more are set up.