|
44 | 44 | %% parse interface
|
45 | 45 | -export([convert_uri/1]).
|
46 | 46 | -export([tokens/1]).
|
| 47 | +-export([get_authenticate/1]). |
47 | 48 |
|
48 | 49 | -export([set_chdr/3,
|
49 | 50 | set_shdr/3]).
|
|
60 | 61 | make_response/4,
|
61 | 62 | auth_basic_encode/2,
|
62 | 63 | url_encode/1,
|
63 |
| - make_headers/2 |
| 64 | + make_headers/2, |
| 65 | + make_basic_request/2, |
| 66 | + make_digest_request/2 |
64 | 67 | ]).
|
65 | 68 | -export([url_decode/1,
|
66 | 69 | parse_query/1]).
|
| 70 | +-export([make_digest_response/3]). |
| 71 | + |
67 | 72 |
|
68 | 73 | -import(lists, [reverse/1]).
|
69 | 74 |
|
| 75 | +-define(Q, $\"). |
70 | 76 | %%
|
71 | 77 | %% Perform a HTTP/1.1 GET
|
72 | 78 | %%
|
@@ -909,10 +915,39 @@ auth_basic_encode(User,undefined) ->
|
909 | 915 | auth_basic_encode(User,Pass) ->
|
910 | 916 | base64:encode_to_string(to_list(User)++":"++to_list(Pass)).
|
911 | 917 |
|
912 |
| -make_headers(undefined, _Pass) -> []; |
913 |
| -make_headers(User, Pass) -> |
| 918 | +make_headers(User, Pass) -> %% bad name should go |
| 919 | + make_basic_request(User, Pass). |
| 920 | + |
| 921 | +make_basic_request(undefined, _Pass) -> []; |
| 922 | +make_basic_request(User, Pass) -> |
914 | 923 | [{"Authorization", "Basic "++auth_basic_encode(User, Pass)}].
|
915 | 924 |
|
| 925 | +make_digest_request(undefined, _Params) -> []; |
| 926 | +make_digest_request(User, Params) -> |
| 927 | + [{"Authorization", "Digest " ++ |
| 928 | + make_param(<<"username">>,User) ++ |
| 929 | + lookup_param(<<"realm">>, Params) ++ |
| 930 | + lookup_param(<<"nonce">>, Params) ++ |
| 931 | + lookup_param(<<"uri">>, Params) ++ |
| 932 | + lookup_param(<<"response">>, Params)}]. |
| 933 | + |
| 934 | +make_param(Key, Value) -> |
| 935 | + to_key(Key)++"="++to_value(Value). |
| 936 | + |
| 937 | +lookup_param(Key, List) -> |
| 938 | + case proplists:get_value(Key, List) of |
| 939 | + undefined -> []; |
| 940 | + Value -> ", "++make_param(Key, Value) |
| 941 | + end. |
| 942 | + |
| 943 | +to_key(Bin) when is_binary(Bin) -> binary_to_list(Bin); |
| 944 | +to_key(List) when is_list(List) -> List. |
| 945 | + |
| 946 | +to_value(Bin) when is_binary(Bin) -> [?Q]++binary_to_list(Bin)++[?Q]; |
| 947 | +to_value(List) when is_list(List) -> [?Q]++List++[?Q]; |
| 948 | +to_value(Atom) when is_atom(Atom) -> atom_to_list(Atom); |
| 949 | +to_value(Int) when is_integer(Int) -> integer_to_list(Int). |
| 950 | + |
916 | 951 | %%
|
917 | 952 | %% Url encode a string
|
918 | 953 | %%
|
@@ -1138,3 +1173,57 @@ tokens(undefined) ->
|
1138 | 1173 | tokens(Line) ->
|
1139 | 1174 | string:tokens(string:to_lower(Line), ";").
|
1140 | 1175 |
|
| 1176 | + |
| 1177 | +%% Read and parse WWW-Authenticate header value |
| 1178 | +get_authenticate(undefined) -> |
| 1179 | + {none,[]}; |
| 1180 | +get_authenticate(<<>>) -> |
| 1181 | + {none,[]}; |
| 1182 | +get_authenticate(<<$\s,Cs/binary>>) -> |
| 1183 | + get_authenticate(Cs); |
| 1184 | +get_authenticate(<<"Basic ",Cs/binary>>) -> |
| 1185 | + {basic, get_params(Cs)}; |
| 1186 | +get_authenticate(<<"Digest ",Cs/binary>>) -> |
| 1187 | + {digest, get_params(Cs)}; |
| 1188 | +get_authenticate(List) when is_list(List) -> |
| 1189 | + get_authenticate(list_to_binary(List)). |
| 1190 | + |
| 1191 | +get_params(Bin) -> |
| 1192 | + Ps = binary:split(Bin, <<" ">>, [global]), |
| 1193 | + [ case binary:split(P, <<"=">>) of |
| 1194 | + [K,V] -> {K,unq(V)}; |
| 1195 | + [K] -> {K,true} |
| 1196 | + end || P <- Ps, P =/= <<>> ]. |
| 1197 | + |
| 1198 | +%% "unquote" a string or a binary |
| 1199 | +unq(String) when is_binary(String) -> unq(binary_to_list(String)); |
| 1200 | +unq([$\s|Cs]) -> unq(Cs); |
| 1201 | +unq([?Q|Cs]) -> unq_(Cs); |
| 1202 | +unq(Cs) -> Cs. |
| 1203 | + |
| 1204 | +unq_([?Q|_]) -> []; |
| 1205 | +unq_([C|Cs]) -> [C|unq_(Cs)]; |
| 1206 | +unq_([]) -> []. |
| 1207 | + |
| 1208 | +make_digest_response(Cred, Method, AuthParams) -> |
| 1209 | + Nonce = proplists:get_value(<<"nonce">>,AuthParams,""), |
| 1210 | + DigestUriValue = proplists:get_value(<<"uri">>,AuthParams,""), |
| 1211 | + %% FIXME! Verify Nonce!!! |
| 1212 | + A1 = a1(Cred), |
| 1213 | + HA1 = hex(crypto:md5(A1)), |
| 1214 | + A2 = a2(Method, DigestUriValue), |
| 1215 | + HA2 = hex(crypto:md5(A2)), |
| 1216 | + hex(kd(HA1, Nonce++":"++HA2)). |
| 1217 | + |
| 1218 | +a1({digest,_Path,User,Password,Realm}) -> |
| 1219 | + iolist_to_binary([User,":",Realm,":",Password]). |
| 1220 | + |
| 1221 | +a2(Method, Uri) -> |
| 1222 | + iolist_to_binary([atom_to_list(Method),":",Uri]). |
| 1223 | + |
| 1224 | +kd(Secret, Data) -> |
| 1225 | + crypto:md5([Secret,":",Data]). |
| 1226 | + |
| 1227 | +hex(Bin) -> |
| 1228 | + [ element(X+1, {$0,$1,$2,$3,$4,$5,$6,$7,$8,$9,$a,$b,$c,$d,$e,$f}) || |
| 1229 | + <<X:4>> <= Bin ]. |
0 commit comments