From e8cccaa937d43301d53e1c481e2fa0d8e53a1164 Mon Sep 17 00:00:00 2001
From: Vivian Zhang <vivian.zhang@intel.com>
Date: Fri, 6 Aug 2010 00:18:42 -0400
Subject: [PATCH] Add changeing password interface to API

---
 src/api/app/controllers/person_controller.rb  |   48 +++++++++++++++++++++++++
 src/api/config/routes.rb                      |    2 +
 src/api/lib/active_rbac_mixins/user_mixins.rb |   36 ++++++++++++++++++
 3 files changed, 86 insertions(+), 0 deletions(-)

diff --git a/src/api/app/controllers/person_controller.rb b/src/api/app/controllers/person_controller.rb
index fd5bddc..52ff54f 100644
--- a/src/api/app/controllers/person_controller.rb
+++ b/src/api/app/controllers/person_controller.rb
@@ -167,4 +167,52 @@ class PersonController < ApplicationController
     end
     true
   end
+
+  def change_my_password
+    if !@http_user
+      logger.debug "No user logged in, permission to changing password denied"
+      @errorcode = 401
+      @summary = "No user logged in, permission to changing password denied"
+      render :template => 'error', :status => 401
+    else
+      if not params[:login] or not params[:password]
+        render_error :status => 404, :errorcode => 'failed to change password',
+              :message => "Failed to change password: missing parameter"
+        return
+      end
+    end
+
+    login = URI.unescape( params[:login] )
+    newpassword = Base64.decode64(URI.unescape( params[:password]))
+
+    #change password to LDAP if LDAP is enabled    
+    if defined?( LDAP_MODE ) && LDAP_MODE == :on
+      require 'base64'
+      begin
+        logger.debug( "Using LDAP to change password for #{login}" )
+        result = User.change_password_ldap(login, newpassword)
+      rescue Exception
+          logger.debug "LDAP_MODE selected but 'ruby-ldap' module not installed."
+      end
+      if result
+        render_error :status => 404, :errorcode => 'failed to change password to ldap', :message => "Failed to change password to ldap: #{result}"
+        return
+      end
+    end
+
+    #update password in users db
+    @user = User.find_by_login(login)
+    if @user.blank?
+      logger.debug "User is not valid!"
+      render_error :status => 404, :errorcode => 'unknown_user',
+        :message => "Unknown user: #{login}"
+      return
+    end
+    logger.debug("find the user")
+    @user.password = newpassword
+    @user.password_confirmation = newpassword
+    @user.state = User.states['confirmed']
+    @user.save!
+    render_ok
+  end
 end
diff --git a/src/api/config/routes.rb b/src/api/config/routes.rb
index be303d8..f27faba 100644
--- a/src/api/config/routes.rb
+++ b/src/api/config/routes.rb
@@ -23,6 +23,8 @@ ActionController::Routing::Routes.draw do |map|
   map.connect 'person/register', :controller => 'person', :action => 'register'
   map.connect 'person/:login', :controller => 'person', :action => 'userinfo', :login => /[^\/]*/
   map.connect 'person/:login/group', :controller => 'person', :action => 'grouplist', :login => /[^\/]*/
+  map.connect 'person/:login/passwd/:password', :controller => 'person', :action => 'change_my_password', :login => /[^\/]*/,:password => /[^\/]*/
+
 
   ### /group
   map.connect 'group/:group', :controller => 'group', :action => 'grouplist', :group => /[^\/]*/
diff --git a/src/api/lib/active_rbac_mixins/user_mixins.rb b/src/api/lib/active_rbac_mixins/user_mixins.rb
index 4d1fbe7..6f5462a 100644
--- a/src/api/lib/active_rbac_mixins/user_mixins.rb
+++ b/src/api/lib/active_rbac_mixins/user_mixins.rb
@@ -317,6 +317,42 @@ module UserMixins
             return nil
           end
 
+          # This static method tries to update the password with the given login in the 
+          # active directory server.  Return the error msg if any error occured
+          def self.change_password_ldap(login, password)
+            ldap_con = initialize_ldap_con(LDAP_SEARCH_USER, LDAP_SEARCH_AUTH)
+            if ldap_con.nil?
+              logger.debug( "Unable to connect to LDAP server" )
+              return "Unable to connect to LDAP server"
+            end
+            user_filter = "(#{LDAP_SEARCH_ATTR}=#{login})"
+            dn = String.new
+            ldap_con.search( LDAP_SEARCH_BASE, LDAP::LDAP_SCOPE_SUBTREE, user_filter ) do |entry|
+              dn = entry.dn
+            end
+            if dn.empty?
+              logger.debug( "User not found in ldap" )
+              return "User not found in ldap"
+            end
+
+            require 'digest/md5'
+            require 'base64'
+            ldap_password = "{MD5}"+Base64.b64encode(Digest::MD5.digest(password)).chomp
+            entry = [
+              LDAP.mod(LDAP::LDAP_MOD_REPLACE, LDAP_AUTH_ATTR, [ldap_password]),
+            ]
+            begin
+              ldap_con.modify(dn, entry)
+            rescue LDAP::ResultError
+              logger.debug("Error #{ldap_con.err} for #{login}")
+              return "#{ldap_con.err}"
+            end
+
+            ldap_con.unbind()
+            return
+          end
+
+
           # This static method tries to find a user with the given login and
           # password in the active directory server.  Returns nil unless 
           # credentials are correctly found using LDAP.
-- 
1.6.1
