Safe Haskell | None |
---|---|
Language | Haskell2010 |
- freshRandomName :: Action e s ST
- freshRandom20 :: Action e s Random20
- freshConfirmationToken :: Action e s ConfirmationToken
- freshPasswordResetToken :: Action e s PasswordResetToken
- freshServiceId :: Action e s ServiceId
- freshServiceKey :: Action e s ServiceKey
- freshSessionToken :: Action e s ThentosSessionToken
- freshServiceSessionToken :: Action e s ServiceSessionToken
- lookupConfirmedUser :: UserId -> Action e s (UserId, User)
- lookupConfirmedUserByName :: UserName -> Action e s (UserId, User)
- lookupConfirmedUserByEmail :: UserEmail -> Action e s (UserId, User)
- addUser :: (Show e, Typeable e) => UserFormData -> Action e s UserId
- deleteUser :: UserId -> Action e s ()
- addUnconfirmedUser :: (Show e, Typeable e) => UserFormData -> Action e s (UserId, ConfirmationToken)
- confirmNewUser :: ConfirmationToken -> Action e s (UserId, ThentosSessionToken)
- addPasswordResetToken :: UserEmail -> Action e s (User, PasswordResetToken)
- resetPassword :: PasswordResetToken -> UserPass -> Action e s ()
- changePassword :: UserId -> UserPass -> UserPass -> Action e s ()
- _changePasswordUnconditionally :: UserId -> UserPass -> Action e s ()
- requestUserEmailChange :: UserId -> UserEmail -> (ConfirmationToken -> ST) -> Action e s ()
- confirmUserEmailChange :: ConfirmationToken -> Action e s ()
- allServiceIds :: Action e s [ServiceId]
- lookupService :: ServiceId -> Action e s (ServiceId, Service)
- addService :: UserId -> ServiceName -> ServiceDescription -> Action e s (ServiceId, ServiceKey)
- deleteService :: ServiceId -> Action e s ()
- autocreateServiceIfMissing'P :: UserId -> ServiceId -> Action e s ()
- addPersona :: PersonaName -> UserId -> Maybe Uri -> Action e s Persona
- deletePersona :: Persona -> Action e s ()
- addContext :: ServiceId -> ContextName -> ContextDescription -> Maybe ProxyUri -> Action e s Context
- deleteContext :: Context -> Action e s ()
- registerPersonaWithContext :: Persona -> ServiceId -> ContextName -> Action e s ()
- unregisterPersonaFromContext :: Persona -> ServiceId -> ContextName -> Action e s ()
- findPersona :: UserId -> ServiceId -> ContextName -> Action e s (Maybe Persona)
- contextsForService :: ServiceId -> Action e s [Context]
- addPersonaToGroup :: PersonaId -> Group -> Action e s ()
- removePersonaFromGroup :: PersonaId -> Group -> Action e s ()
- addGroupToGroup :: Group -> Group -> Action e s ()
- removeGroupFromGroup :: Group -> Group -> Action e s ()
- personaGroups :: Persona -> Action e s [Group]
- defaultSessionTimeout :: Timeout
- lookupThentosSession :: ThentosSessionToken -> Action e s ThentosSession
- existsThentosSession :: ThentosSessionToken -> Action e s Bool
- startThentosSessionByUserId :: UserId -> UserPass -> Action e s ThentosSessionToken
- startThentosSessionByUserName :: UserName -> UserPass -> Action e s (UserId, ThentosSessionToken)
- startThentosSessionByUserEmail :: UserEmail -> UserPass -> Action e s (UserId, ThentosSessionToken)
- startThentosSessionByServiceId :: ServiceId -> ServiceKey -> Action e s ThentosSessionToken
- endThentosSession :: ThentosSessionToken -> Action e s ()
- validateThentosUserSession :: ThentosSessionToken -> Action e s (UserId, User)
- serviceNamesFromThentosSession :: ThentosSessionToken -> Action e s [ServiceName]
- lookupServiceSession :: ServiceSessionToken -> Action e s ServiceSession
- existsServiceSession :: ServiceSessionToken -> Action e s Bool
- addServiceRegistration :: ThentosSessionToken -> ServiceId -> Action e s ()
- dropServiceRegistration :: ThentosSessionToken -> ServiceId -> Action e s ()
- startServiceSession :: ThentosSessionToken -> ServiceId -> Action e s ServiceSessionToken
- endServiceSession :: ServiceSessionToken -> Action e s ()
- getServiceSessionMetadata :: ServiceSessionToken -> Action e s ServiceSessionMetadata
- assignRole :: Agent -> Role -> Action e s ()
- unassignRole :: Agent -> Role -> Action e s ()
- agentRoles :: Agent -> Action e s [Role]
- makeCaptcha :: Action e s (CaptchaId, ImageData)
- solveCaptcha :: CaptchaId -> ST -> Action e s Bool
- collectGarbage :: Exception (ActionError e) => Action e s ()
Documentation
freshRandomName :: Action e s ST
Return a base64 encoded random string of length 24 (18 bytes of entropy).
We use _
instead of /
as last letter of the base64 alphabet since it allows using names
within URLs without percent-encoding. Our Base64 alphabet thus consists of ASCII letters +
digits as well as +
and _
. All of these are reliably recognized in URLs, even if they occur
at the end.
RFC 4648 also has a "URL Safe Alphabet" which additionally replaces +
by -
. But that's
problematic, since -
at the end of URLs is not recognized as part of the URL by some programs
such as Thunderbird.
freshRandom20 :: Action e s Random20
Generate 20 bytes of random data. For comparison: an UUID has 16 bytes, so that should be enough for all practical purposes.
freshServiceId :: Action e s ServiceId
freshServiceKey :: Action e s ServiceKey
lookupConfirmedUser :: UserId -> Action e s (UserId, User)
Return a user with its id. Requires or privileges of admin or the user that is looked up. If
no user is found or access is not granted, throw NoSuchUser
. See _lookupUserCheckPassword
for
user lookup prior to authentication.
lookupConfirmedUserByName :: UserName -> Action e s (UserId, User)
Like lookupConfirmedUser
, but based on UserName
.
lookupConfirmedUserByEmail :: UserEmail -> Action e s (UserId, User)
Like lookupConfirmedUser
, but based on UserEmail
.
addUser :: (Show e, Typeable e) => UserFormData -> Action e s UserId
Add a user based on its form data. Requires RoleAdmin
. For creating users with e-mail
verification, see addUnconfirmedUser
, confirmNewUser
.
deleteUser :: UserId -> Action e s ()
Delete user. Requires or privileges of admin or the user that is looked up. If no user is
found or access is not granted, throw NoSuchUser
.
addUnconfirmedUser :: (Show e, Typeable e) => UserFormData -> Action e s (UserId, ConfirmationToken)
Initiate email-verified user creation. Does not require any privileges. See also:
confirmNewUser
.
confirmNewUser :: ConfirmationToken -> Action e s (UserId, ThentosSessionToken)
Finish email-verified user creation. Throws NoSuchPendingUserConfirmation
if the
token doesn't exist or is expired.
SECURITY: As a caller, you have to make sure the token has been produced by the legitimate recipient of a confirmation email. Authentication can only be provided by this api **after** the user has been created by calling this function.
See also: addUnconfirmedUser
.
addPasswordResetToken :: UserEmail -> Action e s (User, PasswordResetToken)
Initiate password reset with email confirmation. No authentication required, obviously.
resetPassword :: PasswordResetToken -> UserPass -> Action e s ()
Finish password reset with email confirmation.
SECURITY: See confirmNewUser
.
changePassword :: UserId -> UserPass -> UserPass -> Action e s ()
Authenticate user against old password, and then change password to new password.
LIO policy: In addition to the old password as proof of authority, this function requires the user to change the password to be logged in (or admin privs).
_changePasswordUnconditionally :: UserId -> UserPass -> Action e s ()
requestUserEmailChange :: UserId -> UserEmail -> (ConfirmationToken -> ST) -> Action e s ()
Initiate email change by creating and storing a token and sending it out by email to the old
address of the user. This requires RoleAdmin
or privs of email address owner, but the address
is only changed after a call to confirmUserEmailChange
with the correct token.
confirmUserEmailChange :: ConfirmationToken -> Action e s ()
Look up the given confirmation token and updates the user's email address iff 1) the token
exists, 2) the token belongs to the user currently logged in, and 3) the token has not
expired. If any of these conditions don't apply, throw NoSuchToken
to avoid leaking
information.
SECURITY: The security information from confirmNewUser
does not directly apply here: the
attacker needs to fulfil **all** three conditions mentioned above for a successful attack, not
only token secrecy.
allServiceIds :: Action e s [ServiceId]
lookupService :: ServiceId -> Action e s (ServiceId, Service)
addService :: UserId -> ServiceName -> ServiceDescription -> Action e s (ServiceId, ServiceKey)
deleteService :: ServiceId -> Action e s ()
autocreateServiceIfMissing'P :: UserId -> ServiceId -> Action e s ()
Autocreate a service with a specific ID if it doesn't exist yet. Moreover, if no contexts have been defined for the service yet, a default context with empty name is automatically created.
This allows adding services to the config which will automatically spring into life if the config is read.
addPersona :: PersonaName -> UserId -> Maybe Uri -> Action e s Persona
Add a new persona to the DB. A persona has a unique name and a user to which it belongs.
The PersonaId
is assigned by the DB. May throw NoSuchUser
or PersonaNameAlreadyExists
.
Only the user owning the persona or an admin may do this.
deletePersona :: Persona -> Action e s ()
Delete a persona. Throw NoSuchPersona
if the persona does not exist in the DB.
Only the user owning the persona or an admin may do this.
addContext :: ServiceId -> ContextName -> ContextDescription -> Maybe ProxyUri -> Action e s Context
Add a new context. The first argument identifies the service to which the context belongs.
May throw NoSuchService
or ContextNameAlreadyExists
.
Only the service or an admin may do this.
deleteContext :: Context -> Action e s ()
Delete a context. Throw an error if the context does not exist in the DB. Only the service owning the context or an admin may do this.
registerPersonaWithContext :: Persona -> ServiceId -> ContextName -> Action e s ()
Connect a persona with a context. Throws an error if the persona is already registered for the
context or if the user has any *other* persona registered for the context
(MultiplePersonasPerContext
). (As we currently allow only one persona per user and context.)
Throws NoSuchPersona
or NoSuchContext
if one of the arguments doesn't exist.
Only the user owning the persona or an admin may do this.
unregisterPersonaFromContext :: Persona -> ServiceId -> ContextName -> Action e s ()
Unregister a persona from accessing a context. No-op if the persona was not registered for the context. Only the user owning the persona or an admin may do this.
findPersona :: UserId -> ServiceId -> ContextName -> Action e s (Maybe Persona)
Find the persona that a user wants to use for a context (if any). Only the user owning the persona or an admin may do this.
contextsForService :: ServiceId -> Action e s [Context]
List all contexts owned by a service. Anybody may do this.
addPersonaToGroup :: PersonaId -> Group -> Action e s ()
Add a persona to a group. If the persona is already a member of the group, do nothing. Only a GroupAdmin may do this.
removePersonaFromGroup :: PersonaId -> Group -> Action e s ()
Remove a persona from a group. If the persona is not a member of the group, do nothing. Only a GroupAdmin may do this.
addGroupToGroup :: Group -> Group -> Action e s ()
Add a group (subgroup) to another group (supergroup) so that all members of subgroup will also
be considered members of supergroup. If subgroup is already a direct member of supergroup, do
nothing. Throws GroupMembershipLoop
if adding the relation would cause a loop.
Only a GroupAdmin may do this.
removeGroupFromGroup :: Group -> Group -> Action e s ()
Remove a group (subgroup) from another group (supergroup). If subgroup is not a direct member of supergroup, do nothing. Only a GroupAdmin may do this.
personaGroups :: Persona -> Action e s [Group]
List all groups a persona belongs to, directly or indirectly. If p is a member of g1, g1 is a member of g2, and g2 is a member of g3, [g1, g2, g3] will be returned. Only the user owning the persona or a GroupAdmin may do this.
defaultSessionTimeout :: Timeout
Thentos and service sessions have a fixed duration of 2 weeks.
FIXME: make configurable, and distinguish between thentos sessions and service sessions. (eventually, this will need to be run-time configurable. but there will probably still be global defaults handled by configifier.)
lookupThentosSession :: ThentosSessionToken -> Action e s ThentosSession
Find ThentosSession
from token. If ThentosSessionToken
does not exist or clearance does
not allow access, throw NoSuchThentosSession
.
existsThentosSession :: ThentosSessionToken -> Action e s Bool
Like lookupThentosSession
, but does not throw an exception if thentos session does not exist
or is inaccessible, but returns False
instead.
startThentosSessionByUserId :: UserId -> UserPass -> Action e s ThentosSessionToken
Check user credentials and create a session for user. Requires lookupConfirmedUser
and
_startThentosSessionByAgent
.
startThentosSessionByUserName :: UserName -> UserPass -> Action e s (UserId, ThentosSessionToken)
Like startThentosSessionByUserId
, but based on UserName
as key.
startThentosSessionByUserEmail :: UserEmail -> UserPass -> Action e s (UserId, ThentosSessionToken)
startThentosSessionByServiceId :: ServiceId -> ServiceKey -> Action e s ThentosSessionToken
Check service credentials and create a session for service.
endThentosSession :: ThentosSessionToken -> Action e s ()
Terminate ThentosSession
. Does not require any label; being in possession of the session
token is enough authentication to terminate it.
validateThentosUserSession :: ThentosSessionToken -> Action e s (UserId, User)
Check that a Thentos session exists, is not expired, and belongs to a user (rather than a
service). Returns information on the user if that's the case. Throws NoSuchThentosSession
otherwise.
We assume that the ThentosSessionToken is a secret that nobody except the session owner can know, therefore no special clearance is required.
serviceNamesFromThentosSession :: ThentosSessionToken -> Action e s [ServiceName]
For a thentos session, look up all service sessions and return their service names. Requires
RoleAdmin
, service, or user privs.
lookupServiceSession :: ServiceSessionToken -> Action e s ServiceSession
Like lookupThentosSession
, but for ServiceSession
s.
existsServiceSession :: ServiceSessionToken -> Action e s Bool
Like existsThentosSession
, but for ServiceSession
s.
addServiceRegistration :: ThentosSessionToken -> ServiceId -> Action e s ()
Register a user with a service. Requires RoleAdmin
or user privs.
FIXME: We do not ask for any authorization from ServiceId
as of now. It is enough to know a
ServiceId
to register with the resp. service. This probably violates integrity of the view of
the service. Fixing this may require credentials handling. Before we do that, we should take a
better look at oauth.
dropServiceRegistration :: ThentosSessionToken -> ServiceId -> Action e s ()
Undo registration of a user with a service. Requires RoleAdmin
or user privs.
See FIXME in addServiceRegistration
.
startServiceSession :: ThentosSessionToken -> ServiceId -> Action e s ServiceSessionToken
Login user running the current thentos session into service. If user is not registered with service, throw an error.
Inherits label and exception behavor from lookupThentosSession
and write-guards for thentos
session owner.
endServiceSession :: ServiceSessionToken -> Action e s ()
Terminate service session. Throws NoSuchServiceSession if the user does not own the session.
getServiceSessionMetadata :: ServiceSessionToken -> Action e s ServiceSessionMetadata
Inherits label from lookupServiceSession
.
assignRole :: Agent -> Role -> Action e s ()
unassignRole :: Agent -> Role -> Action e s ()
agentRoles :: Agent -> Action e s [Role]
makeCaptcha :: Action e s (CaptchaId, ImageData)
Generate a captcha. Returns a pair of CaptchaId
and the binary image data in PNG format.
The correct solution to the captcha is stored in the DB. Does not require any privileges.
solveCaptcha :: CaptchaId -> ST -> Action e s Bool
Submit a solution to a captcha, returning whether or not the solution is correct.
Calling this action deletes the referenced captcha from the DB, so every captcha must be
solved (or not) at first attempt. Throws NoSuchCaptchaId
if the given CaptchaId
doesn't
exist in the DB (either because it never did or because it was deleted due to garbage collection
or a prior call to this action). Does not require any privileges.
collectGarbage :: Exception (ActionError e) => Action e s ()