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_AUTH_WIDGET_H_ 8 #define WT_AUTH_AUTH_WIDGET_H_ 9 10 #include <Wt/WTemplateFormView.h> 11 #include <Wt/Auth/AuthModel.h> 12 #include <Wt/Auth/OAuthService.h> 13 #include <Wt/Auth/RegistrationModel.h> 14 #include <Wt/WDialog.h> 15 #include <Wt/WMessageBox.h> 16 17 namespace Wt { 18 namespace Auth { 19 20 class AbstractUserDatabase; 21 class AuthModel; 22 class Login; 23 class User; 24 25 /*! \class AuthWidget Wt/Auth/AuthWidget.h 26 * \brief An authentication widget. 27 * 28 * The authentication widget is a widget that provides a login or 29 * logout function (depending on whether the user is currently logged 30 * in). You can use it for either or both purposes. 31 * 32 * Login or logout events are signalled to a Login object on which 33 * this widget acts. 34 * 35 * The widget also processes environmental information related to 36 * authentication: 37 * 38 * - email tokens, which are indicated in an internal path. The widget 39 * uses dialogs (by default) to interact with the user to act on the token. 40 * - authentication tokens, which are stored in browser cookies, to implement 41 * remember-me functionality. 42 * 43 * The processEnvironment() method initiates this process, and should 44 * typically be called only at application startup time. 45 * 46 * The authentication widget is implemented as a View for an 47 * AuthModel, which can be set using setModel(). The login logic (at 48 * this moment only for password-based authentication) is handled by 49 * this model. 50 * 51 * It is very likely that the off-the shelf authentication widget does 52 * not satisfy entirely to your taste or functional requirements. The 53 * widget uses three methods to allow customization: 54 * 55 * - as a WTemplateFormView, you may change the layout and styling of 56 * to your liking. 57 * - the authentication logic is delegated to an AuthModel and can 58 * can be specialized or can be used with a custom view altogether. 59 * - the views are created using virtual methods, which may be specialized 60 * to create a customized view or to apply changes to the default view. 61 * 62 * \ingroup auth 63 */ 64 class WT_API AuthWidget : public WTemplateFormView 65 { 66 public: 67 /*! \brief Constructor 68 * 69 * Creates a new authentication widget. This creates an AuthModel 70 * using the given authentication service \p baseAuth and user 71 * database \p users. 72 * 73 * The result of authentication changes is propagated to the rest of 74 * the application using a \p login object. 75 * 76 * Authentication services need to be configured in the model(). 77 */ 78 AuthWidget(const AuthService& baseAuth, AbstractUserDatabase& users, 79 Login& login); 80 81 /*! \brief Constructor. 82 * 83 * Creates a new authentication widget. 84 * 85 * The result of authentication changes is propagated to the rest of 86 * the application using a \p login object. 87 * 88 * You need to call setModel() to configure a model for this view. 89 */ 90 AuthWidget(Login& login); 91 92 ~AuthWidget(); 93 94 /*! \brief Sets a model. 95 * 96 * This sets a model to be used for authentication. 97 */ 98 void setModel(std::unique_ptr<AuthModel> model); 99 100 /*! \brief Returns the model. 101 * 102 * The model is used only for the login function. 103 * 104 * \sa setModel() 105 */ model()106 AuthModel *model() const { return model_.get(); } 107 108 /*! \brief Returns the login object. 109 * 110 * This login object is used to keep track of the user currently 111 * authenticated. 112 */ login()113 Login& login() { return login_; } 114 115 /*! \brief Sets an internal path for authentication services. 116 * 117 * Only the registration function is made available through an 118 * internal path (so that one can redirect a user to the 119 * registration page). Other internal paths involved in 120 * authentication are configured in the service classes: 121 * - AuthService::setEmailRedirectInternalPath(): email tokens 122 * - OAuthService::redirectInternalPath(): an internal path used during 123 * the oauth process. 124 */ 125 void setInternalBasePath(const std::string& path); 126 127 /*! \brief Returns the internal path. 128 * 129 * \sa setInternalBasePath() 130 */ internalBasePath()131 std::string internalBasePath() const { return basePath_; } 132 133 /*! \brief Configures registration capabilities. 134 * 135 * Although the AuthWidget itself does not implement a registration 136 * view, it may offer a button/link to do so, and calls 137 * registerNewUser() when a user wishes to register. 138 * 139 * Even if registration is not enabled, the result of an 140 * OAuthService login process may be that a new user is 141 * identified. Then the createRegistrationView() is also used to 142 * present this new user with a registration view, passing the 143 * information obtained through OAuth. 144 */ 145 void setRegistrationEnabled(bool enabled); 146 147 /*! \brief Starts a new registration process. 148 * 149 * This calls \p registerNewUser(0). 150 */ 151 void registerNewUser(); 152 153 /*! \brief Starts a new registration process. 154 * 155 * This starts a new registration process, and may be called in 156 * response to a user action, an internal path change, or an 157 * OAuthService login procedure which identified a new user. In the 158 * latter case, the OAuth-provided information is passed as 159 * parameter \p oauth. 160 * 161 * The default implementation creates a view using 162 * createRegistrationView(), and shows it in a dialog using 163 * showDialog(). 164 */ 165 virtual void registerNewUser(const Identity& oauth); 166 167 /*! \brief Processes the (initial) environment. 168 * 169 * This method process environmental information that may be 170 * relevant to authentication: 171 * 172 * - email tokens, which are indicated through an internal path. The 173 * widget uses dialogs (by default) to interact with the user to 174 * act on the token. 175 * 176 * - authentication tokens, which are stored in browser cookies, to 177 * implement remember-me functionality. When logging in using an 178 * authentication token, the login is considered "weak" (since a 179 * user may have inadvertently forgotten to logout from a public 180 * computer). You should let the user authenticate using another, 181 * primary method before doing sensitive operations. The 182 * createPasswordPromptDialog() method may be useful for this. 183 * 184 * \sa letUpdatePassword() 185 */ 186 virtual void processEnvironment(); 187 188 /*! \brief Lets the user update his password. 189 * 190 * This creates a view to let the user enter his new password. 191 * 192 * The default implementation creates a new view using 193 * createUpdatePasswordView() and shows it in a dialog using 194 * showDialog(). 195 */ 196 virtual void letUpdatePassword(const User& user, bool promptPassword); 197 198 /*! \brief Lets the user "recover" a lost password. 199 * 200 * This creates a view to let the user enter his email address, used 201 * to send an email containing instructions to enter a new password. 202 * 203 * The default implementation creates a new view using 204 * createLostPasswordView() and shows it in a dialog using 205 * showDialog(). 206 */ 207 virtual void handleLostPassword(); 208 209 /*! \brief Creates a lost password view. 210 * 211 * When email verification has been enabled, the user may indicate 212 * that he has lost his password -- then proof of controlling the same 213 * email address that had associated with his account is sufficient to 214 * allow him to enter a new password. 215 * 216 * This creates the widget used to let the user enter his email 217 * address. The default implementation creates a new 218 * LostPasswordWidget. 219 * 220 * \sa handleLostPassword() 221 */ 222 virtual std::unique_ptr<WWidget> createLostPasswordView(); 223 224 /*! \brief Creates a registration view. 225 * 226 * This creates a registration view, optionally using information 227 * already obtained from a third party identification service (such as 228 * an OAuth provider). 229 * 230 * The default implementation creates a new RegistrationWidget 231 * with a model created using createRegistrationModel(). 232 * 233 * \sa registerNewUser() 234 */ 235 virtual std::unique_ptr<WWidget> createRegistrationView(const Identity& id); 236 237 /*! \brief Creates a view to update a user's password. 238 * 239 * If \p promptPassword is \c true, the user has to enter his current 240 * password in addition to a new password. 241 * 242 * This creates the widget used to let the user chose a new 243 * password. The default implementation instantiates an 244 * UpdatePasswordWidget. 245 * 246 * \sa letUpdatePassword() 247 */ 248 virtual std::unique_ptr<WWidget> 249 createUpdatePasswordView(const User& user, bool promptPassword); 250 251 /*! \brief Creates a password prompt dialog. 252 * 253 * This creates a dialog 254 * password. The user is taken from the \p login object, which also 255 * signals an eventual success using its Login::changed() signal. 256 * 257 * The default implementation instantiates a PasswordPromptDialog. 258 */ 259 virtual std::unique_ptr<WDialog> createPasswordPromptDialog(Login& login); 260 261 void attemptPasswordLogin(); 262 263 /*! \brief Displays the error message. 264 * 265 * This method display an dialog showing the error 266 */ 267 virtual void displayError(const WString& error); 268 269 /*! \brief Displays the info message. 270 * 271 * This method display an dialog showing the info 272 */ 273 virtual void displayInfo(const WString& message); 274 275 protected: 276 /*! \brief Creates the user-interface. 277 * 278 * This method is called just before an initial rendering, and creates 279 * the initial view. 280 * 281 * The default implementation calls createLoginView() or 282 * createLoggedInView() depending on whether a user is currently 283 * logged in. 284 */ 285 virtual void create(); 286 287 /*! \brief Creates the login view. 288 * 289 * This creates a view that allows the user to login, and is shown when 290 * no user is current logged in. 291 * 292 * The default implementation renders the 293 * <tt>"Wt.Auth.template.login"</tt> template, and binds fields 294 * using createPasswordLoginView() and createOAuthLoginView(). 295 */ 296 virtual void createLoginView(); 297 298 /*! \brief Creates the view shown when the user is logged in. 299 * 300 * The default implementation renders the 301 * <tt>"Wt.Auth.template.logged-in"</tt> template. 302 */ 303 virtual void createLoggedInView(); 304 305 /*! \brief Creates a password login view. 306 * 307 * This is used by the default implementation of createLoginView() 308 * to prompt for the information needed for logging in using a 309 * username and password. The default implementation implements a view 310 * guided by the model(). 311 * 312 * \sa createLoginView() 313 */ 314 virtual void createPasswordLoginView(); 315 316 /*! \brief Creates a widget to login using OAuth. 317 * 318 * The default implementation adds an icon for each OAuth service 319 * provider available. The icon that will be used for each service 320 * is a PNG file with a path based on the 321 * \link OAuthService::name name \endlink of the service. If the 322 * name is is "myService", then the icon path will be "css/oauth-myService.png". 323 * Wt does not bundle any icons by default, so you should make sure that 324 * the icon is in place. 325 * 326 * There's a lot to say about making a usable login mechanism for 327 * OAuth (and federated login services in general), see 328 * https://sites.google.com/site/oauthgoog/UXFedLogin. 329 * 330 * \sa createLoginView() 331 */ 332 virtual void createOAuthLoginView(); 333 334 #ifdef WT_HAS_SAML 335 /*! \brief Creates a widget to login using SAML. 336 * 337 * The default implementation adds an icon for each SAML service 338 * provider available. The icon that will be used for each service 339 * is a PNG file with a path based on the 340 * \link Saml::Service::name name \endlink of the service. If the 341 * name is "myService", then the icon path will be "css/saml-myService.png". 342 * Wt does not bundle any icons by default, so you should make sure that 343 * the icon is in place. 344 * 345 * \sa createLoginView() 346 */ 347 virtual void createSamlLoginView(); 348 #endif // WT_HAS_SAML 349 350 /*! \brief Shows a dialog. 351 * 352 * This shows a dialog. The default method creates a standard WDialog, 353 * with the given \p title and \p contents as central widget. 354 * 355 * When the central widget is deleted, it deletes the dialog. 356 */ 357 virtual WDialog *showDialog(const WString& title, 358 std::unique_ptr<WWidget> contents); 359 360 /*! \brief Creates a registration model. 361 * 362 * This method creates a registration model. The default 363 * implementation creates a RegistrationModel() but you may want to 364 * reimplement this function to return a specialized registration 365 * model (complementing a specialized registration view). 366 * 367 * \sa registerNewUser() 368 */ 369 virtual std::unique_ptr<RegistrationModel> createRegistrationModel(); 370 371 virtual std::unique_ptr<WWidget> createFormWidget(AuthModel::Field field) 372 override; 373 374 virtual void render(WFlags<RenderFlag> flags) override; 375 376 private: 377 std::shared_ptr<AuthModel> model_; 378 std::unique_ptr<RegistrationModel> registrationModel_; 379 Login& login_; 380 std::string basePath_; 381 bool registrationEnabled_; 382 383 bool created_; 384 std::unique_ptr<WDialog> dialog_; 385 std::unique_ptr<WMessageBox> messageBox_; 386 387 void init(); 388 void logout(); 389 void loginThrottle(int delay); 390 void closeDialog(); 391 void onLoginChange(); 392 void onPathChange(const std::string& path); 393 bool handleRegistrationPath(const std::string& path); 394 395 void oAuthStateChange(OAuthProcess *process); 396 void oAuthDone(OAuthProcess *process, const Identity& identity); 397 #ifdef WT_HAS_SAML 398 void samlDone(Saml::Process *process, const Identity& identity); 399 #endif // WT_HAS_SAML 400 void updatePasswordLoginView(); 401 }; 402 403 } 404 } 405 406 #endif // WT_AUTH_AUTH_WIDGET_H_ 407