From e001da59198a432037110aca5ea581771257d323 Mon Sep 17 00:00:00 2001 From: Deven Phillips Date: Wed, 4 Nov 2015 17:46:12 -0500 Subject: [PATCH 1/2] Add support for getting WSDL over SSL --- src/scrub.erl | 117 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 86 insertions(+), 31 deletions(-) diff --git a/src/scrub.erl b/src/scrub.erl index 105b9a8..4c5f754 100644 --- a/src/scrub.erl +++ b/src/scrub.erl @@ -12,7 +12,7 @@ -module(scrub). --export([initModel/1, initModel/2, +-export([initModel/1, initModel/4, initModel/3, initModel/2, initModelFile/1, config_file_xsd/0, call/3, call/4, call/5, call/6, call/8, @@ -319,12 +319,21 @@ mk_envelope(Messages, Headers) when is_list(Messages),is_list(Headers) -> %%% Parse a WSDL file and return a 'Model' %%% -------------------------------------------------------------------- initModel(WsdlFile) -> - initModel(WsdlFile, ?DefaultPrefix). + initModel(WsdlFile, ?DefaultPrefix, [], [], false). + +initModel(WsdlFile, Prefix) -> + initModel(WsdlFile, Prefix, [], [], false). + +initModel(WsdlFile, Username, Password) -> + initModel(WsdlFile, ?DefaultPrefix, Username, Password, false). + +initModel(WsdlFile, Username, Password, VerifySSL) -> + initModel(WsdlFile, ?DefaultPrefix, Username, Password, VerifySSL). %% PrefixOrOptions can be a property list that contains the options %% for Erlsom, or a String. If it is a string, this is used as the %% Erlsom 'prefix' option (and the other options are left unspecified). -initModel(WsdlFile, PrefixOrOptions) -> +initModel(WsdlFile, PrefixOrOptions, Username, Password, VerifySSL) -> Options = case is_string(PrefixOrOptions) of no -> %% It is an option list @@ -336,7 +345,7 @@ initModel(WsdlFile, PrefixOrOptions) -> [{prefix, PrefixOrOptions}] end, PrivDir = priv_dir(), - initModel2(WsdlFile, Options, PrivDir, undefined, undefined). + initModel2(WsdlFile, Options, PrivDir, undefined, undefined, Username, Password, VerifySSL). initModelFile(ConfigFile) -> {ok, ConfigSchema} = erlsom:compile_xsd(config_file_xsd()), @@ -346,12 +355,12 @@ initModelFile(ConfigFile) -> wsdl_file = Wsdl, add_files = AddFiles} = Config, #xsd_file{name = WsdlFile, prefix = Prefix, import_specs = Import} = Wsdl, - initModel2(WsdlFile, [{prefix, Prefix}], XsdPath, Import, AddFiles). + initModel2(WsdlFile, [{prefix, Prefix}], XsdPath, Import, AddFiles, [], [], false). priv_dir() -> code:priv_dir(scrub). -initModel2(WsdlFile, ErlsomOptions, Path, Import, AddFiles) -> +initModel2(WsdlFile, ErlsomOptions, Path, Import, AddFiles, Username, Password, VerifySSL) -> WsdlName = filename:join([Path, "wsdl.xsd"]), IncludeWsdl = {"http://schemas.xmlsoap.org/wsdl/", "wsdl", WsdlName}, {ok, WsdlModel} = erlsom:compile_xsd_file( @@ -365,7 +374,7 @@ initModel2(WsdlFile, ErlsomOptions, Path, Import, AddFiles) -> Options = ErlsomOptions ++ makeOptions(Import), %% parse Wsdl {Model, Operations} = parseWsdls([WsdlFile], WsdlModel2, - Options, {undefined, []}), + Options, {undefined, []}, Username, Password, VerifySSL), %% TODO: add files as required %% now compile envelope.xsd, and add Model {ok, EnvelopeModel} = erlsom:compile_xsd_file( @@ -383,14 +392,17 @@ initModel2(WsdlFile, ErlsomOptions, Path, Import, AddFiles) -> %%% Parse a list of WSDLs and import (recursively) %%% Returns {Model, Operations} %%% -------------------------------------------------------------------- -parseWsdls(WsdlFiles, WsdlModel, Options, Acc) -> - parseWsdls(WsdlFiles, WsdlModel, Options, Acc, #namespace_registry{}). +parseWsdls(WsdlFiles, WsdlModel, Options, Acc, Username, Password, VerifySSL) -> + io:format("parseWsdls/7~n"), + parseWsdls(WsdlFiles, WsdlModel, Options, Acc, #namespace_registry{}, Username, Password, VerifySSL). -parseWsdls([], _WsdlModel, _Options, Acc, _NSRegistry) -> +parseWsdls([], _WsdlModel, _Options, Acc, _NSRegistry, _, _, _) -> + io:format("parseWsdls/8~n"), Acc; -parseWsdls([WsdlFile | Tail], WsdlModel, Options, {AccModel, AccOperations}, NSRegistry) -> +parseWsdls([WsdlFile | Tail], WsdlModel, Options, {AccModel, AccOperations}, NSRegistry, Username, Password, VerifySSL) -> + io:format("parseWsdls/8-2~n"), WsdlFileNoSpaces = rmsp(WsdlFile), - {ok, WsdlFileContent} = get_url_file(WsdlFileNoSpaces), + {ok, WsdlFileContent} = get_url_file(WsdlFileNoSpaces, Username, Password, VerifySSL), {ok, ParsedWsdl, _} = erlsom:scan(WsdlFileContent, WsdlModel), WsdlTargetNameSpace = getTargetNamespaceFromWsdl(ParsedWsdl), {Prefix, PrefixlessOptions} = remove_prefix_option(Options), @@ -415,7 +427,7 @@ parseWsdls([WsdlFile | Tail], WsdlModel, Options, {AccModel, AccOperations}, NSR %% this makes it a bit easier to deal with imported wsdl's. %% TODO uncomment if imports can be WSDL %%Acc3 = parseWsdls(Imports, WsdlModel, Options, Acc2, ImportsEnrichedNSRegistry), - parseWsdls(Tail, WsdlModel, PrefixlessOptions, Acc2, ImportsEnrichedNSRegistry). + parseWsdls(Tail, WsdlModel, PrefixlessOptions, Acc2, ImportsEnrichedNSRegistry, [], [], false). remove_prefix_option(Options) -> case lists:keytake(prefix, 1, Options) of @@ -508,27 +520,70 @@ addSchemaFiles([Xsd| Tail], AccModel, Options, ImportList) -> end, addSchemaFiles(Tail, Model2, Options, ImportList). +%%% -------------------------------------------------------------------- +%%% Make a list of headers from username/password +%%% -------------------------------------------------------------------- +make_headers(Username, Password) -> + case {Username, Password} of + {Username, []} -> + %%% Invalid condition + []; + {[], Password} -> + %%% Invalid condition + []; + {Username, Password} -> + Encoded = base64:encode_to_string(Username++":"++Password), + [{"Authorization", "Basic " ++ Encoded}] + end. + %%% -------------------------------------------------------------------- %%% Get a file from an URL spec. %%% -------------------------------------------------------------------- -get_url_file("http://"++_ = URL) -> - case httpc:request(URL) of - {ok,{{_HTTP,200,_OK}, _Headers, Body}} -> - {ok, Body}; - {ok,{{_HTTP,RC,Emsg}, _Headers, _Body}} -> - error_logger:error_msg("~p: http-request got: ~p~n", - [?MODULE, {RC, Emsg}]), - {error, "failed to retrieve: "++URL}; - {error, Reason} -> - error_logger:error_msg("~p: http-request failed: ~p~n", - [?MODULE, Reason]), - {error, "failed to retrieve: "++URL} - end; -get_url_file("file://"++Fname) -> +get_url_file("http://"++_ = URL, Username, Password, _) -> + io:format("get_url_file/4-http~n"), + case httpc:request(get, {URL, make_headers(Username, Password)}, [{timeout, 5000}], []) of + {ok,{{_HTTP,200,_OK}, _Headers, Body}} -> + {ok, Body}; + {ok,{{_HTTP,RC,Emsg}, _Headers, _Body}} -> + error_logger:error_msg("~p: http-request got: ~p~n", + [?MODULE, {RC, Emsg}]), + {error, "failed to retrieve: "++URL}; + {error, Reason} -> + error_logger:error_msg("~p: http-request failed: ~p~n", + [?MODULE, Reason]), + {error, "failed to retrieve: "++URL} + end; +get_url_file("https://"++_ = URL, Username, Password, VerifySSL=false) -> + io:format("get_url_file/4-https~n"), + HTTPOptions = case VerifySSL of + false -> + [{ssl, [{verify, 0}]}, {timeout, 5000}]; + _ -> + [{timeout, 5000}] + end, + io:format("HTTPS Options"), + RetVal = case httpc:request(get, {URL, make_headers(Username, Password)}, HTTPOptions, []) of + {ok,{{_HTTP,200,_OK}, _Headers, Body}} -> + io:format("Got 200 OK~n"), + {ok, Body}; + {ok,{{_HTTP,RC,Emsg}, _Headers, _Body}} -> + error_logger:error_msg("~p: http-request got: ~p~n", + [?MODULE, {RC, Emsg}]), + {error, "failed to retrieve: "++URL}; + {error, Reason} -> + error_logger:error_msg("~p: http-request failed: ~p~n", + [?MODULE, Reason]), + {error, "failed to retrieve: "++URL}; + Anything -> + error_logger:error_msg("~p: Unknown error: ~p~n", [?MODULE, Anything]) + end, + io:format("Completed HTTP(S) request~n"), + RetVal; +get_url_file("file://"++Fname, _, _, _) -> {ok, Bin} = file:read_file(Fname), {ok, binary_to_list(Bin)}; %% added this, since this is what is used in many WSDLs (i.e.: just a filename). -get_url_file(Fname) -> +get_url_file(Fname, _, _, _) -> {ok, Bin} = file:read_file(Fname), {ok, binary_to_list(Bin)}. @@ -549,11 +604,11 @@ http_request(URL, Action, Request, Options, Headers, ContentType) -> end. inets_request(URL, Action, Request, Options, Headers, ContentType) -> - case Action of + NHeaders = case Action of undefined -> - NHeaders = Headers; + Headers; _ -> - NHeaders = [{"SOAPAction", Action} | Headers] + [{"SOAPAction", Action} | Headers] end, NewHeaders = case proplists:get_value("Host", NHeaders) of undefined -> From 8867ac0094c3bb0403a6573701a5cbfd305cd12d Mon Sep 17 00:00:00 2001 From: Deven Phillips Date: Wed, 4 Nov 2015 17:53:29 -0500 Subject: [PATCH 2/2] Remove debug io:format calls --- src/scrub.erl | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/scrub.erl b/src/scrub.erl index 4c5f754..561c958 100644 --- a/src/scrub.erl +++ b/src/scrub.erl @@ -393,14 +393,11 @@ initModel2(WsdlFile, ErlsomOptions, Path, Import, AddFiles, Username, Password, %%% Returns {Model, Operations} %%% -------------------------------------------------------------------- parseWsdls(WsdlFiles, WsdlModel, Options, Acc, Username, Password, VerifySSL) -> - io:format("parseWsdls/7~n"), parseWsdls(WsdlFiles, WsdlModel, Options, Acc, #namespace_registry{}, Username, Password, VerifySSL). parseWsdls([], _WsdlModel, _Options, Acc, _NSRegistry, _, _, _) -> - io:format("parseWsdls/8~n"), Acc; parseWsdls([WsdlFile | Tail], WsdlModel, Options, {AccModel, AccOperations}, NSRegistry, Username, Password, VerifySSL) -> - io:format("parseWsdls/8-2~n"), WsdlFileNoSpaces = rmsp(WsdlFile), {ok, WsdlFileContent} = get_url_file(WsdlFileNoSpaces, Username, Password, VerifySSL), {ok, ParsedWsdl, _} = erlsom:scan(WsdlFileContent, WsdlModel), @@ -540,7 +537,6 @@ make_headers(Username, Password) -> %%% Get a file from an URL spec. %%% -------------------------------------------------------------------- get_url_file("http://"++_ = URL, Username, Password, _) -> - io:format("get_url_file/4-http~n"), case httpc:request(get, {URL, make_headers(Username, Password)}, [{timeout, 5000}], []) of {ok,{{_HTTP,200,_OK}, _Headers, Body}} -> {ok, Body}; @@ -554,17 +550,14 @@ get_url_file("http://"++_ = URL, Username, Password, _) -> {error, "failed to retrieve: "++URL} end; get_url_file("https://"++_ = URL, Username, Password, VerifySSL=false) -> - io:format("get_url_file/4-https~n"), HTTPOptions = case VerifySSL of false -> [{ssl, [{verify, 0}]}, {timeout, 5000}]; _ -> [{timeout, 5000}] end, - io:format("HTTPS Options"), RetVal = case httpc:request(get, {URL, make_headers(Username, Password)}, HTTPOptions, []) of {ok,{{_HTTP,200,_OK}, _Headers, Body}} -> - io:format("Got 200 OK~n"), {ok, Body}; {ok,{{_HTTP,RC,Emsg}, _Headers, _Body}} -> error_logger:error_msg("~p: http-request got: ~p~n", @@ -577,7 +570,6 @@ get_url_file("https://"++_ = URL, Username, Password, VerifySSL=false) -> Anything -> error_logger:error_msg("~p: Unknown error: ~p~n", [?MODULE, Anything]) end, - io:format("Completed HTTP(S) request~n"), RetVal; get_url_file("file://"++Fname, _, _, _) -> {ok, Bin} = file:read_file(Fname),