1 // This may look like C code, but it's really -*- C++ -*-
2 /*
3  * Copyright (C) 2011 Emweb bv, Herent, Belgium.
4  *
5  * See the LICENSE file for terms of use.
6  */
7 #ifndef WT_AUTH_REGISTRATION_MODEL_H_
8 #define WT_AUTH_REGISTRATION_MODEL_H_
9 
10 #include <Wt/Auth/Identity.h>
11 #include <Wt/Auth/FormBaseModel.h>
12 #include <Wt/Auth/User.h>
13 
14 namespace Wt {
15   namespace Auth {
16 
17 /*! \brief Enumeration for an email policy
18  */
19 enum class EmailPolicy {
20   Disabled,  //!< The email address is not asked for
21   Optional,  //!< A user may optionally provide an email address
22   Mandatory  //!< A user must provide an email address
23 };
24 
25 /*! \brief Method for confirming to be an existing user.
26  */
27 enum class IdentityConfirmationMethod {
28   ConfirmWithPassword,    //!< Confirm using a password prompt
29   ConfirmWithEmail,       //!< Confirm by using an email procedure
30   ConfirmationNotPossible //!< Confirmation is not possible
31 };
32 
33 class Login;
34 
35 /*! \class RegistrationModel Wt/Auth/RegistrationModel.h
36  *  \brief Model for implementing a registration view.
37  *
38  * This model implements the logic for the registration of a new user.
39  * It can deal with traditional username/password registration, or
40  * registration of pre-identified users using federated login.
41  *
42  * The model exposes four fields:
43  * - LoginNameField: the login name (used as an identity for the
44  *   Identity::LoginName provider) -- this can be an email if the
45  *   AuthService is configured to use email addresses as identity
46  * - ChoosePasswordField: the password
47  * - RepeatPasswordField: the password (repeated)
48  * - EmailField: if an email address is to be asked (and is not used
49  *   as identity).
50  *
51  * The largest complexity is in the handling of third party identity
52  * providers, which is initiated with a call to registerIdentified().
53  *
54  * When a user is re-identified with the same identity, then the model
55  * may require that the (original) user confirms this new
56  * identity. The model indicates that this button should be made
57  * visible with isConfirmUserButtonVisible(), the action to take is
58  * determined by confirmIsExistingUser(), and existingUserConfirmed()
59  * ends this process by merging the new identity into the existing
60  * user.
61  *
62  * \sa RegistrationWidget
63  *
64  * \ingroup auth
65  */
66 class WT_API RegistrationModel : public FormBaseModel
67 {
68 public:
69   //! \brief Choose Password field
70   static const Field ChoosePasswordField;
71 
72   //! \brief Repeat password field
73   static const Field RepeatPasswordField;
74 
75   //! \brief Email field (if login name is not email)
76   static const Field EmailField;
77 
78   /*! \brief Constructor.
79    *
80    * Creates a new registration model, using a basic authentication
81    * service and user database.
82    *
83    * The \p login object is used to indicate that an existing user was
84    * re-identified, and thus the registration process may be aborted.
85    */
86   RegistrationModel(const AuthService& baseAuth, AbstractUserDatabase& users,
87 		    Login& login);
88 
89   /*! \brief Resets the model.
90    *
91    * This resets the model to initial values, clearing any entered information
92    * (login name, password, pre-identified identity).
93    */
94   virtual void reset() override;
95 
96   /*! \brief Returns the login object.
97    */
login()98   Login& login() { return login_; }
99 
100   /*! \brief Configures a minimum length for a login name.
101    *
102    * The default value is 4.
103    */
setMinLoginNameLength(int chars)104   void setMinLoginNameLength(int chars) { minLoginNameLength_ = chars; }
105 
106   /*! \brief Returns the minimum length for a login name.
107    *
108    * \sa setMinLoginNameLength()
109    */
minLoginNameLength()110   int minLoginNameLength() const { return minLoginNameLength_; }
111 
112   /*! \brief Configures whether an email address needs to be entered.
113    *
114    * You may specify whether you want the user to enter an email
115    * address.
116    *
117    * This has no effect when the IdentityPolicy is
118    * IdentityPolicy::EmailAddress.
119    *
120    * The default policy is:
121    * - EmailOptional when email address verification is enabled
122    * - EmailDisabled otherwise
123    */
124   void setEmailPolicy(EmailPolicy policy);
125 
126   /*! \brief Returns the email policy.
127    *
128    * \sa setEmailPolicy()
129    */
emailPolicy()130   EmailPolicy emailPolicy() const { return emailPolicy_; }
131 
132   /*! \brief Register a user authenticated by an identity provider.
133    *
134    * Using a 3rd party authentication service such as %OAuth, a user
135    * may be identified which is not yet registered with the web
136    * application.
137    *
138    * Then, you may still need to allow the user to complete
139    * registration, but because the user already is identified and
140    * authenticated, this simplifies the registration form, since
141    * fields related to authentication can be dropped.
142    *
143    * Returns \c true if the given identity was already registered, and
144    * has been logged in.
145    */
146   virtual bool registerIdentified(const Identity& identity);
147 
148   /*! \brief Returns the existing user that needs to be confirmed.
149    *
150    * When a user wishes to register with an identity that corresponds
151    * to an existing user, he may be allowd to confirm that he is in
152    * fact this existing user.
153    *
154    * \sa confirmIsExistingUser()
155    */
existingUser()156   User existingUser() const { return existingUser_; }
157 
158   /*! \brief Returns the method to be used to confirm to be an existing user.
159    *
160    * When the ConfirmExisting field is visible, this returns an
161    * appropriate method to use to let the user confirm that he is
162    * indeed the identified existing user.
163    *
164    * The outcome of this method (if it is an online method, like a
165    * password prompt), if successful, should be indicated using
166    * existingUserConfirmed().
167    *
168    * \sa existingUserConfirmed()
169    */
170   virtual IdentityConfirmationMethod confirmIsExistingUser() const;
171 
172   /*! \brief Confirms that the user is indeed an existing user.
173    *
174    * The new identity is added to this existing user (if applicable),
175    * and the user is logged in.
176    */
177   virtual void existingUserConfirmed();
178 
179   /*! \brief Validates the login name.
180    *
181    * This verifies that the login name is adequate (see also
182    * setMinLoginNameLength()).
183    */
184   virtual WString validateLoginName(const WT_USTRING& userName) const;
185 
186   /*! \brief Verifies that a user with that name does not yet exist.
187    *
188    * If a user with that name already exists, it may in fact be the
189    * same user that is trying to register again (perhaps using a
190    * different identification method). If possible, we allow the user
191    * to confirm his identity.
192    */
193   virtual void checkUserExists(const WT_USTRING& userName);
194 
195   /*! \brief Performs the registration process.
196    */
197   virtual User doRegister();
198 
199   virtual bool isVisible(Field field) const override;
200   virtual bool isReadOnly(Field field) const override;
201   virtual bool validateField(Field field) override;
202 
203   /*! \brief Returns whether an existing user needs to be confirmed.
204    *
205    * This returns whether the user is being identified as an existing
206    * user and he can confirm that he is in fact the same user.
207    */
208   virtual bool isConfirmUserButtonVisible() const;
209 
210   /*! \brief Returns whether federated login options can be shown.
211    *
212    * This returns whether fields for federated login (such as OAuth)
213    * should be shown. These are typically buttons corresponding to
214    * identity providers.
215    *
216    * The result of a federated authentication procedure should be
217    * indicated to registerIdentified().
218    */
219   virtual bool isFederatedLoginVisible() const;
220 
221   static void validatePasswordsMatchJS(WLineEdit *password,
222 				       WLineEdit *password2,
223 				       WText *info2);
224 
225 private:
226   Login& login_;
227   int minLoginNameLength_;
228   EmailPolicy emailPolicy_;
229 
230   Identity idpIdentity_;
231   User existingUser_;
232 };
233 
234   }
235 }
236 
237 #endif // WT_AUTH_REGISTRATION_MODEL_H_
238