1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 2012-2013. All Rights Reserved. 5: %% 6: %% The contents of this file are subject to the Erlang Public License, 7: %% Version 1.1, (the "License"); you may not use this file except in 8: %% compliance with the License. You should have received a copy of the 9: %% Erlang Public License along with this software. If not, it can be 10: %% retrieved online at http://www.erlang.org/. 11: %% 12: %% Software distributed under the License is distributed on an "AS IS" 13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 14: %% the License for the specific language governing rights and limitations 15: %% under the License. 16: %% 17: %% %CopyrightEnd% 18: %% 19: 20: -module(eldap_basic_SUITE). 21: 22: -compile(export_all). 23: 24: %%-include_lib("common_test/include/ct.hrl"). 25: -include_lib("test_server/include/test_server.hrl"). 26: -include_lib("eldap/include/eldap.hrl"). 27: 28: -define(TIMEOUT, 120000). % 2 min 29: 30: init_per_suite(Config) -> 31: StartSsl = try ssl:start() 32: catch 33: Error:Reason -> 34: {skip, lists:flatten(io_lib:format("eldap init_per_suite failed to start ssl Error=~p Reason=~p", [Error, Reason]))} 35: end, 36: case StartSsl of 37: ok -> 38: chk_config(ldap_server, {"localhost",9876}, 39: chk_config(ldaps_server, {"localhost",9877}, 40: Config)); 41: _ -> 42: StartSsl 43: end. 44: 45: end_per_suite(_Config) -> 46: ok. 47: 48: init_per_testcase(_TestCase, Config0) -> 49: {EldapHost,Port} = proplists:get_value(ldap_server,Config0), 50: try 51: {ok, Handle} = eldap:open([EldapHost], [{port,Port}]), 52: ok = eldap:simple_bind(Handle, "cn=Manager,dc=ericsson,dc=se", "hejsan"), 53: {ok, MyHost} = inet:gethostname(), 54: Path = "dc="++MyHost++",dc=ericsson,dc=se", 55: eldap:add(Handle,"dc=ericsson,dc=se", 56: [{"objectclass", ["dcObject", "organization"]}, 57: {"dc", ["ericsson"]}, {"o", ["Testing"]}]), 58: eldap:add(Handle,Path, 59: [{"objectclass", ["dcObject", "organization"]}, 60: {"dc", [MyHost]}, {"o", ["Test machine"]}]), 61: [{eldap_path,Path}|Config0] 62: catch error:{badmatch,Error} -> 63: io:format("Eldap init error ~p~n ~p~n",[Error, erlang:get_stacktrace()]), 64: {skip, lists:flatten(io_lib:format("Ldap init failed with host ~p:~p. Error=~p", [EldapHost,Port,Error]))} 65: end. 66: 67: end_per_testcase(_TestCase, Config) -> 68: {EHost, Port} = proplists:get_value(ldap_server, Config), 69: Path = proplists:get_value(eldap_path, Config), 70: {ok, H} = eldap:open([EHost], [{port, Port}]), 71: ok = eldap:simple_bind(H, "cn=Manager,dc=ericsson,dc=se", "hejsan"), 72: case eldap:search(H, [{base, Path}, 73: {filter, eldap:present("objectclass")}, 74: {scope, eldap:wholeSubtree()}]) 75: of 76: {ok, {eldap_search_result, Entries, _}} -> 77: [ok = eldap:delete(H, Entry) || {eldap_entry, Entry, _} <- Entries]; 78: _ -> ignore 79: end, 80: 81: ok. 82: 83: %% suite() -> 84: 85: all() -> 86: [app, 87: api, 88: ssl_api, 89: start_tls, 90: tls_operations, 91: start_tls_twice, 92: start_tls_on_ssl 93: ]. 94: 95: app(doc) -> "Test that the eldap app file is ok"; 96: app(suite) -> []; 97: app(Config) when is_list(Config) -> 98: ok = test_server:app_test(public_key). 99: 100: api(doc) -> "Basic test that all api functions works as expected"; 101: api(suite) -> []; 102: api(Config) -> 103: {Host,Port} = proplists:get_value(ldap_server, Config), 104: {ok, H} = eldap:open([Host], [{port,Port}]), 105: %% {ok, H} = eldap:open([Host], [{port,Port+1}, {ssl, true}]), 106: do_api_checks(H, Config), 107: eldap:close(H), 108: ok. 109: 110: 111: ssl_api(doc) -> "Basic test that all api functions works as expected"; 112: ssl_api(suite) -> []; 113: ssl_api(Config) -> 114: {Host,Port} = proplists:get_value(ldaps_server, Config), 115: {ok, H} = eldap:open([Host], [{port,Port}, {ssl,true}]), 116: do_api_checks(H, Config), 117: eldap:close(H), 118: ok. 119: 120: 121: start_tls(doc) -> "Test that an existing (tcp) connection can be upgraded to tls"; 122: start_tls(suite) -> []; 123: start_tls(Config) -> 124: {Host,Port} = proplists:get_value(ldap_server, Config), 125: {ok, H} = eldap:open([Host], [{port,Port}]), 126: ok = eldap:start_tls(H, [ 127: {keyfile, filename:join([proplists:get_value(data_dir,Config), 128: "certs/client/key.pem"])} 129: ]), 130: eldap:close(H). 131: 132: 133: tls_operations(doc) -> "Test that an upgraded connection is usable for ldap stuff"; 134: tls_operations(suite) -> []; 135: tls_operations(Config) -> 136: {Host,Port} = proplists:get_value(ldap_server, Config), 137: {ok, H} = eldap:open([Host], [{port,Port}]), 138: ok = eldap:start_tls(H, [ 139: {keyfile, filename:join([proplists:get_value(data_dir,Config), 140: "certs/client/key.pem"])} 141: ]), 142: do_api_checks(H, Config), 143: eldap:close(H). 144: 145: start_tls_twice(doc) -> "Test that start_tls on an already upgraded connection fails"; 146: start_tls_twice(suite) -> []; 147: start_tls_twice(Config) -> 148: {Host,Port} = proplists:get_value(ldap_server, Config), 149: {ok, H} = eldap:open([Host], [{port,Port}]), 150: ok = eldap:start_tls(H, []), 151: {error,tls_already_started} = eldap:start_tls(H, []), 152: do_api_checks(H, Config), 153: eldap:close(H). 154: 155: 156: start_tls_on_ssl(doc) -> "Test that start_tls on an ldaps connection fails"; 157: start_tls_on_ssl(suite) -> []; 158: start_tls_on_ssl(Config) -> 159: {Host,Port} = proplists:get_value(ldaps_server, Config), 160: {ok, H} = eldap:open([Host], [{port,Port}, {ssl,true}]), 161: {error,tls_already_started} = eldap:start_tls(H, []), 162: do_api_checks(H, Config), 163: eldap:close(H). 164: 165: 166: %%%-------------------------------------------------------------------------------- 167: chk_config(Key, Default, Config) -> 168: case catch ct:get_config(ldap_server, undefined) of 169: undefined -> [{Key,Default} | Config ]; 170: {'EXIT',_} -> [{Key,Default} | Config ]; 171: Value -> [{Key,Value} | Config] 172: end. 173: 174: 175: 176: do_api_checks(H, Config) -> 177: BasePath = proplists:get_value(eldap_path, Config), 178: 179: All = fun(Where) -> 180: eldap:search(H, #eldap_search{base=Where, 181: filter=eldap:present("objectclass"), 182: scope= eldap:wholeSubtree()}) 183: end, 184: {ok, #eldap_search_result{entries=[_XYZ]}} = All(BasePath), 185: %% ct:log("XYZ=~p",[_XYZ]), 186: {error, noSuchObject} = All("cn=Bar,"++BasePath), 187: 188: {error, _} = eldap:add(H, "cn=Jonas Jonsson," ++ BasePath, 189: [{"objectclass", ["person"]}, 190: {"cn", ["Jonas Jonsson"]}, {"sn", ["Jonsson"]}]), 191: eldap:simple_bind(H, "cn=Manager,dc=ericsson,dc=se", "hejsan"), 192: 193: chk_add(H, BasePath), 194: {ok,FB} = chk_search(H, BasePath), 195: chk_modify(H, FB), 196: chk_delete(H, BasePath), 197: chk_modify_dn(H, FB). 198: 199: 200: chk_add(H, BasePath) -> 201: ok = eldap:add(H, "cn=Jonas Jonsson," ++ BasePath, 202: [{"objectclass", ["person"]}, 203: {"cn", ["Jonas Jonsson"]}, {"sn", ["Jonsson"]}]), 204: {error, entryAlreadyExists} = eldap:add(H, "cn=Jonas Jonsson," ++ BasePath, 205: [{"objectclass", ["person"]}, 206: {"cn", ["Jonas Jonsson"]}, {"sn", ["Jonsson"]}]), 207: ok = eldap:add(H, "cn=Foo Bar," ++ BasePath, 208: [{"objectclass", ["person"]}, 209: {"cn", ["Foo Bar"]}, {"sn", ["Bar"]}, {"telephoneNumber", ["555-1232", "555-5432"]}]), 210: ok = eldap:add(H, "ou=Team," ++ BasePath, 211: [{"objectclass", ["organizationalUnit"]}, 212: {"ou", ["Team"]}]). 213: 214: chk_search(H, BasePath) -> 215: Search = fun(Filter) -> 216: eldap:search(H, #eldap_search{base=BasePath, 217: filter=Filter, 218: scope=eldap:singleLevel()}) 219: end, 220: JJSR = {ok, #eldap_search_result{entries=[#eldap_entry{}]}} = Search(eldap:equalityMatch("sn", "Jonsson")), 221: JJSR = Search(eldap:substrings("sn", [{any, "ss"}])), 222: FBSR = {ok, #eldap_search_result{entries=[#eldap_entry{object_name=FB}]}} = 223: Search(eldap:substrings("sn", [{any, "a"}])), 224: FBSR = Search(eldap:substrings("sn", [{initial, "B"}])), 225: FBSR = Search(eldap:substrings("sn", [{final, "r"}])), 226: F_AND = eldap:'and'([eldap:present("objectclass"), eldap:present("ou")]), 227: {ok, #eldap_search_result{entries=[#eldap_entry{}]}} = Search(F_AND), 228: F_NOT = eldap:'and'([eldap:present("objectclass"), eldap:'not'(eldap:present("ou"))]), 229: {ok, #eldap_search_result{entries=[#eldap_entry{}, #eldap_entry{}]}} = Search(F_NOT), 230: {ok,FB}. %% FIXME 231: 232: chk_modify(H, FB) -> 233: Mod = [eldap:mod_replace("telephoneNumber", ["555-12345"]), 234: eldap:mod_add("description", ["Nice guy"])], 235: %% io:format("MOD ~p ~p ~n",[FB, Mod]), 236: ok = eldap:modify(H, FB, Mod), 237: %% DELETE ATTR 238: ok = eldap:modify(H, FB, [eldap:mod_delete("telephoneNumber", [])]). 239: 240: 241: chk_delete(H, BasePath) -> 242: {error, entryAlreadyExists} = eldap:add(H, "cn=Jonas Jonsson," ++ BasePath, 243: [{"objectclass", ["person"]}, 244: {"cn", ["Jonas Jonsson"]}, {"sn", ["Jonsson"]}]), 245: ok = eldap:delete(H, "cn=Jonas Jonsson," ++ BasePath), 246: {error, noSuchObject} = eldap:delete(H, "cn=Jonas Jonsson," ++ BasePath). 247: 248: chk_modify_dn(H, FB) -> 249: ok = eldap:modify_dn(H, FB, "cn=Niclas Andre", true, ""). 250: %%io:format("Res ~p~n ~p~n",[R, All(BasePath)]). 251: 252: 253: %%%---------------- 254: add(H, Attr, Value, Path0, Attrs, Class) -> 255: Path = case Path0 of 256: [] -> Attr ++ "=" ++ Value; 257: _ -> Attr ++ "=" ++ Value ++ "," ++ Path0 258: end, 259: case eldap:add(H, Path, [{"objectclass", Class}, {Attr, [Value]}] ++ Attrs) 260: of 261: ok -> {ok, Path}; 262: {error, E = entryAlreadyExists} -> {E, Path}; 263: R = {error, Reason} -> 264: io:format("~p:~p: ~s,~s =>~n ~p~n", 265: [?MODULE,?LINE, Attr, Value, R]), 266: exit({ldap, add, Reason}) 267: end. 268: 269: 270: 271: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 272: %% Develop 273: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 274: 275: test() -> 276: run(). 277: 278: run() -> 279: Cases = all(), 280: run(Cases). 281: 282: run(Case) when is_atom(Case) -> 283: run([Case]); 284: run(Cases) when is_list(Cases) -> 285: Run = fun(Test, Config0) -> 286: Config = init_per_testcase(Test, Config0), 287: try 288: io:format("~nTest ~p ... ",[Test]), 289: ?MODULE:Test(Config), 290: end_per_testcase(Test, Config), 291: io:format("ok~n",[]) 292: catch _:Reason -> 293: io:format("~n FAIL (~p): ~p~n ~p~n", 294: [Test, Reason, erlang:get_stacktrace()]) 295: end 296: end, 297: process_flag(trap_exit, true), 298: Pid = spawn_link(fun() -> 299: case init_per_suite([]) of 300: {skip, Reason} -> io:format("Skip ~s~n",[Reason]); 301: Config -> 302: try 303: [Run(Test, Config) || Test <- Cases] 304: catch _:Err -> 305: io:format("Error ~p in ~p~n",[Err, erlang:get_stacktrace()]) 306: end, 307: end_per_suite(Config) 308: end 309: end), 310: receive 311: {'EXIT', Pid, normal} -> ok; 312: Msg -> io:format("Received ~p (~p)~n",[Msg, Pid]) 313: after 100 -> ok end, 314: process_flag(trap_exit, false), 315: ok.