aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorMarcus Arendt <[email protected]>2014-11-03 15:52:36 +0100
committerMarcus Arendt <[email protected]>2014-11-03 15:52:36 +0100
commitc3d006f6542e924c73dbfc76da64dacbeeeadfd0 (patch)
treed9b05e614f3466d9d907c57134ce2a0e1511b435 /lib
parent5ab95c910b3d0ea2c102f5b6d081e1a548176ec0 (diff)
parent4130dc841ca68e16f5d97e89653fa49b16f4e793 (diff)
downloadotp-c3d006f6542e924c73dbfc76da64dacbeeeadfd0.tar.gz
otp-c3d006f6542e924c73dbfc76da64dacbeeeadfd0.tar.bz2
otp-c3d006f6542e924c73dbfc76da64dacbeeeadfd0.zip
Merge branch 'danielwhite/eldap-password-modify/OTP-12282'
* danielwhite/eldap-password-modify/OTP-12282: eldap: Add support for modifying passwords
Diffstat (limited to 'lib')
-rw-r--r--lib/eldap/asn1/ELDAPv3.asn112
-rw-r--r--lib/eldap/doc/src/eldap.xml40
-rw-r--r--lib/eldap/src/eldap.erl77
-rw-r--r--lib/eldap/test/eldap_basic_SUITE.erl18
4 files changed, 147 insertions, 0 deletions
diff --git a/lib/eldap/asn1/ELDAPv3.asn1 b/lib/eldap/asn1/ELDAPv3.asn1
index 72b87d7221..3fe7e815cc 100644
--- a/lib/eldap/asn1/ELDAPv3.asn1
+++ b/lib/eldap/asn1/ELDAPv3.asn1
@@ -274,5 +274,17 @@ IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
responseName [0] LDAPOID OPTIONAL,
responseValue [1] OCTET STRING OPTIONAL }
+-- Extended syntax for Password Modify (RFC 3062, Section 2)
+
+-- passwdModifyOID OBJECT IDENTIFIER ::= 1.3.6.1.4.1.4203.1.11.1
+
+PasswdModifyRequestValue ::= SEQUENCE {
+ userIdentity [0] OCTET STRING OPTIONAL,
+ oldPasswd [1] OCTET STRING OPTIONAL,
+ newPasswd [2] OCTET STRING OPTIONAL }
+
+PasswdModifyResponseValue ::= SEQUENCE {
+ genPasswd [0] OCTET STRING OPTIONAL }
+
END
diff --git a/lib/eldap/doc/src/eldap.xml b/lib/eldap/doc/src/eldap.xml
index 4417551aa8..718a8afeec 100644
--- a/lib/eldap/doc/src/eldap.xml
+++ b/lib/eldap/doc/src/eldap.xml
@@ -214,6 +214,46 @@ filter() See present/1, substrings/2,
</desc>
</func>
<func>
+ <name>modify_password(Handle, Dn, NewPasswd) -> ok | {ok, GenPasswd} | {error, Reason}</name>
+ <fsummary>Modify the password of a user.</fsummary>
+ <type>
+ <v>Dn = string()</v>
+ <v>NewPasswd = string()</v>
+ </type>
+ <desc>
+ <p>Modify the password of a user. See <seealso marker="#modify_password/4">modify_password/4</seealso>.</p>
+ </desc>
+ </func>
+ <func>
+ <name>modify_password(Handle, Dn, NewPasswd, OldPasswd) -> ok | {ok, GenPasswd} | {error, Reason}</name>
+ <fsummary>Modify the password of a user.</fsummary>
+ <type>
+ <v>Dn = string()</v>
+ <v>NewPasswd = string()</v>
+ <v>OldPasswd = string()</v>
+ <v>GenPasswd = string()</v>
+ </type>
+ <desc>
+ <p>Modify the password of a user.</p>
+ <list type="bulleted">
+ <item>
+ <p><c>Dn</c>. The user to modify. Should be "" if the
+ modify request is for the user of the LDAP session.</p>
+ </item>
+ <item>
+ <p><c>NewPasswd</c>. The new password to set. Should be ""
+ if the server is to generate the password. In this case,
+ the result will be <c>{ok, GenPasswd}</c>.</p>
+ </item>
+ <item>
+ <p><c>OldPasswd</c>. Sometimes required by server policy
+ for a user to change their password. If not required, use
+ <seealso marker="#modify_password/3">modify_password/3</seealso>.</p>
+ </item>
+ </list>
+ </desc>
+ </func>
+ <func>
<name>modify_dn(Handle, Dn, NewRDN, DeleteOldRDN, NewSupDN) -> ok | {error, Reason}</name>
<fsummary>Modify the DN of an entry.</fsummary>
<type>
diff --git a/lib/eldap/src/eldap.erl b/lib/eldap/src/eldap.erl
index 3fa440d37d..66f80d8d8f 100644
--- a/lib/eldap/src/eldap.erl
+++ b/lib/eldap/src/eldap.erl
@@ -12,6 +12,7 @@
-vc('$Id$ ').
-export([open/1,open/2,simple_bind/3,controlling_process/2,
start_tls/2, start_tls/3,
+ modify_password/3, modify_password/4,
getopts/2,
baseObject/0,singleLevel/0,wholeSubtree/0,close/1,
equalityMatch/2,greaterOrEqual/2,lessOrEqual/2,
@@ -94,6 +95,23 @@ start_tls(Handle, TlsOptions, Timeout) ->
recv(Handle).
%%% --------------------------------------------------------------------
+%%% Modify the password of a user.
+%%%
+%%% Dn - Name of the entry to modify. If empty, the session user.
+%%% NewPasswd - New password. If empty, the server returns a new password.
+%%% OldPasswd - Original password for server verification, may be empty.
+%%%
+%%% Returns: ok | {ok, GenPasswd} | {error, term()}
+%%% --------------------------------------------------------------------
+modify_password(Handle, Dn, NewPasswd) ->
+ modify_password(Handle, Dn, NewPasswd, []).
+
+modify_password(Handle, Dn, NewPasswd, OldPasswd)
+ when is_pid(Handle), is_list(Dn), is_list(NewPasswd), is_list(OldPasswd) ->
+ send(Handle, {passwd_modify,optional(Dn),optional(NewPasswd),optional(OldPasswd)}),
+ recv(Handle).
+
+%%% --------------------------------------------------------------------
%%% Ask for option values on the socket.
%%% Warning: This is an undocumented function for testing purposes only.
%%% Use at own risk...
@@ -505,6 +523,11 @@ loop(Cpid, Data) ->
send(From,Res),
?MODULE:loop(Cpid, NewData);
+ {From, {passwd_modify,Dn,NewPasswd,OldPasswd}} ->
+ {Res,NewData} = do_passwd_modify(Data, Dn, NewPasswd, OldPasswd),
+ send(From, Res),
+ ?MODULE:loop(Cpid, NewData);
+
{_From, close} ->
unlink(Cpid),
exit(closed);
@@ -795,6 +818,60 @@ do_modify_0(Data, Obj, Mod) ->
check_reply(Data#eldap{id = Id}, Resp, modifyResponse).
%%% --------------------------------------------------------------------
+%%% PasswdModifyRequest
+%%% --------------------------------------------------------------------
+
+-define(PASSWD_MODIFY_OID, "1.3.6.1.4.1.4203.1.11.1").
+
+do_passwd_modify(Data, Dn, NewPasswd, OldPasswd) ->
+ case catch do_passwd_modify_0(Data, Dn, NewPasswd, OldPasswd) of
+ {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data};
+ {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data};
+ {ok,NewData} -> {ok,NewData};
+ {ok,Passwd,NewData} -> {{ok, Passwd},NewData};
+ Else -> {ldap_closed_p(Data, Else),Data}
+ end.
+
+do_passwd_modify_0(Data, Dn, NewPasswd, OldPasswd) ->
+ Req = #'PasswdModifyRequestValue'{userIdentity = Dn,
+ oldPasswd = OldPasswd,
+ newPasswd = NewPasswd},
+ log2(Data, "modify password request = ~p~n", [Req]),
+ {ok, Bytes} = 'ELDAPv3':encode('PasswdModifyRequestValue', Req),
+ ExtReq = #'ExtendedRequest'{requestName = ?PASSWD_MODIFY_OID,
+ requestValue = Bytes},
+ Id = bump_id(Data),
+ log2(Data, "extended request = ~p~n", [ExtReq]),
+ Reply = request(Data#eldap.fd, Data, Id, {extendedReq, ExtReq}),
+ log2(Data, "modify password reply = ~p~n", [Reply]),
+ exec_passwd_modify_reply(Data#eldap{id = Id}, Reply).
+
+exec_passwd_modify_reply(Data, {ok,Msg}) when
+ Msg#'LDAPMessage'.messageID == Data#eldap.id ->
+ case Msg#'LDAPMessage'.protocolOp of
+ {extendedResp, Result} ->
+ case Result#'ExtendedResponse'.resultCode of
+ success ->
+ case Result#'ExtendedResponse'.responseValue of
+ asn1_NOVALUE ->
+ {ok, Data};
+ Value ->
+ case 'ELDAPv3':decode('PasswdModifyResponseValue', Value) of
+ {ok,#'PasswdModifyResponseValue'{genPasswd = Passwd}} ->
+ {ok, Passwd, Data};
+ Error ->
+ throw(Error)
+ end
+ end;
+ Error ->
+ {error, {response,Error}}
+ end;
+ Other -> {error, Other}
+ end;
+exec_passwd_modify_reply(_, Error) ->
+ {error, Error}.
+
+%%% --------------------------------------------------------------------
%%% modifyDNRequest
%%% --------------------------------------------------------------------
diff --git a/lib/eldap/test/eldap_basic_SUITE.erl b/lib/eldap/test/eldap_basic_SUITE.erl
index d87f3ac4ac..7f2be54b71 100644
--- a/lib/eldap/test/eldap_basic_SUITE.erl
+++ b/lib/eldap/test/eldap_basic_SUITE.erl
@@ -200,6 +200,7 @@ do_api_checks(H, Config) ->
chk_add(H, BasePath),
{ok,FB} = chk_search(H, BasePath),
chk_modify(H, FB),
+ chk_modify_password(H, FB),
chk_delete(H, BasePath),
chk_modify_dn(H, FB).
@@ -250,6 +251,23 @@ chk_modify(H, FB) ->
%% DELETE ATTR
ok = eldap:modify(H, FB, [eldap:mod_delete("telephoneNumber", [])]).
+chk_modify_password(H, FB) ->
+ %% Change password, and ensure we can bind with it.
+ ok = eldap:simple_bind(H, "cn=Manager,dc=ericsson,dc=se", "hejsan"),
+ ok = eldap:modify_password(H, FB, "example"),
+ ok = eldap:simple_bind(H, FB, "example"),
+ %% Change password to a server generated value.
+ ok = eldap:simple_bind(H, "cn=Manager,dc=ericsson,dc=se", "hejsan"),
+ {ok, Passwd} = eldap:modify_password(H, FB, []),
+ ok = eldap:simple_bind(H, FB, Passwd),
+ %% Change own password to server generated value.
+ {ok, NewPasswd} = eldap:modify_password(H, [], [], Passwd),
+ ok = eldap:simple_bind(H, FB, NewPasswd),
+ %% Change own password to explicit value.
+ ok = eldap:modify_password(H, [], "example", NewPasswd),
+ ok = eldap:simple_bind(H, FB, "example"),
+ %% Restore original binding.
+ ok = eldap:simple_bind(H, "cn=Manager,dc=ericsson,dc=se", "hejsan").
chk_delete(H, BasePath) ->
{error, entryAlreadyExists} = eldap:add(H, "cn=Jonas Jonsson," ++ BasePath,