#8 6-password-change: Added self-service pw change
Merged a year ago by firstyear. Opened a year ago by firstyear.
firstyear/389-ds-portal 6-password-change  into  master

file modified
+85 -6
@@ -161,9 +161,9 @@ 

      inst = _get_ds_instance(CONFIG['ldapurl'], dn, token)

      try:

          inst.open()

-     # except Exception as e:

-     #     app.logger.debug(e)

-     #     return '', 500

+     except Exception as e:

+         app.logger.debug(e)

+         return '', 500

      finally:

          pass

  
@@ -171,14 +171,93 @@ 

          nsaccts = nsUserAccounts(inst, CONFIG['basedn'], rdn=None)

          acct = nsaccts.get(dn=req_dn)

          acct.ensure_attr_state(state)

-     # except Exception as e:

-     #     app.logger.debug(e)

-     #     return '', 500

+     except Exception as e:

+         app.logger.debug(e)

+         return '', 500

+     finally:

+         inst.unbind_s()

+ 

+     return '', 200

+ 

+ @app.route('/account/<req_dn>/_password', methods=['PUT'])

+ def account_dn_password_update(req_dn):

+     try:

+         dn = session['dn']

+         enc_token = session['token']

+         app.logger.debug(f'{enc_token}')

+         token = FERNET.decrypt(enc_token).decode()

+     except Exception as e:

+         app.logger.debug(e)

+         app.logger.error('Failed to decrypt auth token or get account details.')

+         # TODO: Put a session invalid message here.

+         return redirect(url_for('login'))

+ 

+     # Extract the content

+     cur_pw = None

+     new_pw = None

+     conf_new_pw = None

+     for val in request.json:

+         if val["name"] == "currentpassword":

+             cur_pw = val["value"]

+         elif val["name"] == "newpassword":

+             new_pw = val["value"]

+         elif val["name"] == "confirmnewpassword":

+             conf_new_pw = val["value"]

+         else:

+             pass

+ 

+     # Check the content for basic sanity.

+     if cur_pw is None or new_pw is None or conf_new_pw is None:

+         return '', 500

+ 

+     if new_pw != conf_new_pw:

+         return '', 500

+ 

+     # Seems okay, lets do it.

+     inst = _get_ds_instance(CONFIG['ldapurl'], dn, token)

+     try:

+         inst.open()

+     except Exception as e:

+         app.logger.debug(e)

+         return '', 500

+     finally:

+         pass

+ 

+     try:

+         nsaccts = nsUserAccounts(inst, CONFIG['basedn'], rdn=None)

+         acct = nsaccts.get(dn=req_dn)

+         acct.change_password(cur_pw, new_pw)

+ 

+         # WARNING: Because we current have the pw in the token, we need to re-issue it here else

+         # we'd log the user out. In the futur version when fernet comes from 389-ds, this won't

+         # be needed!

+         token = FERNET.encrypt(str.encode(new_pw))

+         session['token'] = token

+ 

+     except Exception as e:

+         app.logger.debug(e)

+         return '', 500

      finally:

          inst.unbind_s()

  

      return '', 200

  

+ @app.route('/_password', methods=['GET'])

+ def index_password():

+     try:

+         dn = session['dn']

+         enc_token = session['token']

+         app.logger.debug(f'{enc_token}')

+         token = FERNET.decrypt(enc_token).decode()

+     except Exception as e:

+         app.logger.debug(e)

+         app.logger.error('Failed to decrypt auth token or get account details.')

+         # TODO: Put a session invalid message here.

+         return redirect(url_for('login'))

+ 

+     app.logger.debug(f'{dn}, {token}')

+     return render_template('password.html', dn=dn)

+ 

  @app.route('/', methods=['GET'])

  def index():

      # Are they authenticated?

@@ -0,0 +1,91 @@ 

+ 

+ {% extends "base.html" %}

+ 

+ 

+ {% block content %}

+ <div class="container-fluid h-100">

+     <div class="row align-items-stretch">

+         <div class="col-md-2 pt-2 align-items-stretch " style="background: #70e1ec">

+             <nav class="nav nav-tabs flex-column">

+                 <a href="#" class="nav-item nav-link active">My Account</a>

+                 <a href="/logout" class="nav-item nav-link">Logout</a>

+             </nav>

+         </div>

+         <div class="col-md-6 pt-5">

+             <div class="w-75 pb-5">

+                 <form role="form" id="mform">

+                     <h4>Account: {{ dn }}</h4>

+                     <table class="table">

+                         <tbody>

+                             <tr>

+                                 <div class="form-group">

+                                     <td>

+                                         <label for="cur_password">Current Password</label>

+                                     </td>

+                                     <td>

+                                         <input type="password" class="form-control" id="currentpassword" name="currentpassword" placeholder="Current Password">

+                                     </td>

+                                 </div>

+                             </tr>

+                             <tr>

+                                 <div class="form-group">

+                                 <td>

+                                     <label for="cur_password">New Password</label>

+                                 </td>

+                                 <td>

+                                     <input type="password" class="form-control" id="newpassword" name="newpassword" placeholder="New Password">

+                                 </td>

+                                 </div>

+                             </tr>

+                             <tr>

+                                 <div class="form-group">

+                                 <td>

+                                     <label for="cur_password">Confirm New Password</label>

+                                 </td>

+                                 <td>

+                                     <input type="password" class="form-control" id="confirmnewpassword" name="confirmnewpassword" placeholder="Confirm New Password">

+                                 </td>

+                                 </div>

+                             </tr>

+                         </tbody>

+                     </table>

+                     <div class="d-flex justify-content-end">

+                         <button type="button" class="btn btn-success" onclick="ds_submit_form()">

+                             Submit Password Change

+                         </button>

+                     </div>

+                 </form>

+             </div>

+         </div>

+         <div class="col-md-4 pt-5">

+             <div id="alertarea"></div>

+             <h2>Password Change</h2>

+             <p>

+                 Whargarbel

+             </p>

+         </div>

+     </div>

+ </div>

+ 

+ <script>

+ 

+ function ds_submit_form() {

+     var formData = JSON.stringify($("#mform").serializeArray());

+     $.ajax({

+       type: "PUT",

+       url: "/account/{{ dn }}/_password",

+       data: formData,

+       success: function(){

+         $(location).attr('href','/')

+       },

+       dataType: "json",

+       contentType : "application/json"

+     });

+     // According to someone this prevents the page reload?

+     return false;

+ }

+ 

+ </script>

+ 

+ {% endblock %}

+ 

file modified
+9
@@ -78,6 +78,15 @@ 

                                      </div>

                                  </tr>

                              {% endfor %}

+                             <tr>

+                                 <td>

+                                     <label for="userpassword">Password</label>

+                                 </td>

+                                 <td>

+                                     <a href="/_password" class="btn btn-warning">Change Password</a>

+                                 </td>

+                             </tr>

+ 

                          </tbody>

                      </table>

                      <div class="d-flex justify-content-end">

This adds most of the core mechanism, the webui is a little unpolished, but it works.

Going to merge this as there seems to be no objections, and I want a working POC this week.

Pull-Request has been merged by firstyear

a year ago