thentos-core-0.0.1.1: The swiss army knife of privacy-preserving identity management

Safe HaskellNone
LanguageHaskell2010

Thentos.Action

Synopsis

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.

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.

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).

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.

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.

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.

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.

assignRole :: Agent -> Role -> Action e s ()

unassignRole :: Agent -> Role -> Action e s ()

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.