-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/


-- | Authentication plugin for Yesod.
--   
--   This package is the Yesod.Auth.HashDB plugin, originally included as
--   part of yesod-auth, but now modified to be more secure and placed in a
--   separate package.
--   
--   It provides authentication using hashed passwords stored in a
--   database, and works best in situations where an administrator is
--   involved in setting up a user with an initial password.
--   
--   The complete login process, including a default form, is implemented
--   by this plugin, but the application developer must design the
--   interfaces for setting up users and allowing them to change their own
--   passwords, since only the low-level password-setting functions are
--   provided by this package. (Note that other authentication plugins may
--   be more appropriate if you wish to use email verification to set up
--   accounts).
@package yesod-auth-hashdb
@version 1.7.1.2


-- | A Yesod authentication plugin designed to look users up in a
--   Persistent database where the hash of their password is stored.
--   
--   <b>Releases 1.6 finishes the process of removing compatibility with
--   old</b> <b>(pre 1.3) databases. Please see</b>
--   <b><a>https://github.com/paul-rouse/yesod-auth-hashdb/blob/master/Upgrading.md</a></b>
--   
--   To use this in a Yesod application, the foundation data type must be
--   an instance of YesodPersist, and the username and hashed passwords
--   should be added to the database. The following steps give an outline
--   of what is required.
--   
--   You need a database table to store user records: in a scaffolded site
--   it might look like:
--   
--   <pre>
--   User
--       name Text             -- user name used to uniquely identify users
--       password Text Maybe   -- password hash for HashDB
--       UniqueUser name
--   </pre>
--   
--   Create an instance of <a>HashDBUser</a> for this data type:
--   
--   <pre>
--   import Yesod.Auth.HashDB (HashDBUser(..))
--   ....
--   instance HashDBUser User where
--       userPasswordHash = userPassword
--       setPasswordHash h u = u { userPassword = Just h }
--   </pre>
--   
--   In the YesodAuth instance declaration for your app, include
--   <a>authHashDB</a> like so:
--   
--   <pre>
--   import Yesod.Auth.HashDB (authHashDB)
--   ....
--   instance YesodAuth App where
--       ....
--       authPlugins _ = [ authHashDB (Just . UniqueUser), .... ]
--       getAuthId creds = ... -- Perhaps modify scaffolding: see below
--   </pre>
--   
--   The argument to <a>authHashDB</a> is a function which takes a
--   <a>Text</a> and produces a <a>Maybe</a> containing a <a>Unique</a>
--   value to look up in the User table. The example <tt>(Just .
--   UniqueUser)</tt> shown here works for the model outlined above.
--   
--   In the scaffolding, the definition of <tt>getAuthId</tt> contains code
--   to add a user who is not already in the database. Depending on how
--   users are administered, this may not make sense when using HashDB, so
--   consider whether it should be removed.
--   
--   For a real application, the developer should provide some sort of of
--   administrative interface for setting passwords; it needs to call
--   <a>setPassword</a> and save the result in the database. However, if
--   you need to initialise the database by hand, you can generate the
--   correct password hash as follows:
--   
--   <pre>
--   ghci -XOverloadedStrings
--   &gt; import Yesod.Auth.Util.PasswordStore
--   &gt; makePassword "MyPassword" 17
--   </pre>
--   
--   where "17" is the default strength parameter (<a>defaultStrength</a>)
--   used in this module.
--   
--   <h2>Custom Login Form</h2>
--   
--   Instead of using the built-in HTML form, a custom one can be supplied
--   by using <a>authHashDBWithForm</a> instead of <a>authHashDB</a>.
--   
--   The custom form needs to be given as a function returning a Widget,
--   since it has to build in the supplied "action" URL, and it must
--   provide two text fields called "username" and "password". For example,
--   the following modification of the outline code given above would
--   replace the default form with a very minimal one which has no labels
--   and a simple layout.
--   
--   <pre>
--   instance YesodAuth App where
--       ....
--       authPlugins _ = [ authHashDBWithForm myform (Just . UniqueUser), .... ]
--   
--   myform :: Route App -&gt; Widget
--   myform action = $(whamletFile "templates/loginform.hamlet")
--   </pre>
--   
--   where templates/loginform.hamlet contains
--   
--   <pre>
--   &lt;form method="post" action="@{action}"&gt;
--       &lt;input name="username"&gt;
--       &lt;input type="password" name="password"&gt;
--       &lt;input type="submit" value="Login"&gt;
--   </pre>
--   
--   If a CSRF token needs to be embedded in a custom form, code must be
--   included in the widget to add it - see <tt>defaultForm</tt> in the
--   source code of this module for an example.
--   
--   <h2>JSON Interface</h2>
--   
--   This plugin provides sufficient tools to build a complete JSON-based
--   authentication flow. We assume that a design goal is to avoid URLs
--   being built into the client, so all of the URLs needed are passed in
--   JSON data.
--   
--   To start the process, Yesod's defaultErrorHandler produces a JSON
--   response if the HTTP Accept header gives "application/json" precedence
--   over HTML. For a NotAuthenticated error, the status is 401 and the
--   response contains the URL to use for authentication: this is the route
--   which will be handled by the loginHandler method of the YesodAuth
--   instance, which normally returns a login form.
--   
--   Leaving the loginHandler aside for a moment, the final step -
--   supported by this plugin since version 1.6 - is to POST the
--   credentials for authentication in a JSON object. This object must
--   include the properties "username" and "password". In the HTML case
--   this would be the form submission, but here we want to use JSON
--   instead.
--   
--   In a JSON interface, the purpose of the loginHandler is to tell the
--   client the URL for submitting the credentials. This requires a custom
--   loginHandler, since the default one generates HTML only. It can find
--   the correct URL by using the <a>submitRouteHashDB</a> function defined
--   in this module.
--   
--   Writing the loginHandler is made a little messy by the fact that its
--   type allows only HTML content. A work-around is to send JSON as a
--   short-circuit response, but we still make the choice using selectRep
--   so as to get its matching of content types. Here is an example which
--   is geared around using HashDB on its own, supporting both JSON and
--   HTML clients:
--   
--   <pre>
--   instance YesodAuth App where
--      ....
--      loginHandler = do
--           submission &lt;- submitRouteHashDB
--           render &lt;- lift getUrlRender
--           typedContent@(TypedContent ct _) &lt;- selectRep $ do
--               provideRepType typeHtml $ return emptyContent
--                              -- Dummy: the real Html version is at the end
--               provideJson $ object [("loginUrl", toJSON $ render submission)]
--           when (ct == typeJson) $
--               sendResponse typedContent   -- Short-circuit JSON response
--           defaultLoginHandler             -- Html response
--   </pre>
module Yesod.Auth.HashDB

-- | The type representing user information stored in the database should
--   be an instance of this class. It just provides the getter and setter
--   used by the functions in this module.
class HashDBUser user

-- | Getter used by <a>validatePass</a> and <a>upgradePasswordHash</a> to
--   retrieve the password hash from user data
userPasswordHash :: HashDBUser user => user -> Maybe Text

-- | Setter used by <a>setPassword</a> and <a>upgradePasswordHash</a>.
--   Produces a version of the user data with the hash set to the new
--   value.
setPasswordHash :: HashDBUser user => Text -> user -> user

-- | Default strength used for passwords (see
--   <a>Yesod.Auth.Util.PasswordStore</a> for details).
defaultStrength :: Int

-- | Set password for user, using the given strength setting. Use this
--   function, or <a>setPassword</a>, to produce a user record containing
--   the hashed password. Unlike previous versions of this module, no
--   separate salt field is required for new passwords (but it may still be
--   required for compatibility while old password hashes remain in the
--   database).
--   
--   This function does not change the database; the calling application is
--   responsible for saving the data which is returned.
setPasswordStrength :: (MonadIO m, HashDBUser user) => Int -> Text -> user -> m user

-- | As <a>setPasswordStrength</a>, but using the <a>defaultStrength</a>
setPassword :: (MonadIO m, HashDBUser user) => Text -> user -> m user

-- | Validate a plaintext password against the hash in the user data
--   structure.
--   
--   The result distinguishes two types of validation failure, which may be
--   useful in an application which supports multiple authentication
--   methods:
--   
--   <ul>
--   <li>Just False - the user has a password set up, but the given one
--   does not match it</li>
--   <li>Nothing - the user does not have a password
--   (<a>userPasswordHash</a> returns Nothing)</li>
--   </ul>
--   
--   Since 1.4.1
validatePass :: HashDBUser u => u -> Text -> Maybe Bool

-- | Upgrade existing user credentials to a stronger hash. The existing
--   hash will have been produced from a weaker setting in the current
--   algorithm. Use this function to produce an updated user record to
--   store in the database.
--   
--   As of version 1.5 this function cannot be used to upgrade a hash which
--   has a non-empty separate salt field. Such entries would have been
--   produced originally by versions of this module prior to 1.3, but may
--   have been upgraded using earlier versions of this function.
--   
--   Returns Nothing if the user has no password (ie if
--   <a>userPasswordHash</a> u is <a>Nothing</a>) or if the password hash
--   is not in the correct format.
upgradePasswordHash :: (MonadIO m, HashDBUser user) => Int -> user -> m (Maybe user)

-- | Given a user ID and password in plaintext, validate them against the
--   database values. This function simply looks up the user id in the
--   database and calls <a>validatePass</a> to do the work.
validateUser :: HashDBPersist site user => Unique user -> Text -> HandlerFor site Bool

-- | Prompt for username and password, validate that against a database
--   which holds the username and a hash of the password
authHashDB :: HashDBPersist site user => (Text -> Maybe (Unique user)) -> AuthPlugin site

-- | Like <a>authHashDB</a>, but with an extra parameter to supply a custom
--   HTML form.
--   
--   The custom form should be specified as a function which takes a route
--   to use as the form action, and returns a Widget containing the form.
--   The form must use the supplied route as its action URL, and, when
--   submitted, it must send two text fields called "username" and
--   "password".
--   
--   Please see the example in the documentation at the head of this
--   module.
--   
--   Since 1.3.2
authHashDBWithForm :: forall site user. HashDBPersist site user => (Route site -> WidgetFor site ()) -> (Text -> Maybe (Unique user)) -> AuthPlugin site

-- | The route, in the parent site, to which the username and password
--   should be sent in order to log in. This function is particularly
--   useful in constructing a <a>loginHandler</a> function which provides a
--   JSON response. See the "JSON Interface" section above for more
--   details.
--   
--   Since 1.6
submitRouteHashDB :: YesodAuth site => AuthHandler site (Route site)
instance Data.Aeson.Types.FromJSON.FromJSON Yesod.Auth.HashDB.UserPass
