Skip to content

Instantly share code, notes, and snippets.

@fdmanana
Created August 19, 2010 20:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fdmanana/538803 to your computer and use it in GitHub Desktop.
Save fdmanana/538803 to your computer and use it in GitHub Desktop.
% Licensed under the Apache License, Version 2.0 (the "License"); you may not
% use this file except in compliance with the License. You may obtain a copy of
% the License at
%
% http://www.apache.org/licenses/LICENSE-2.0
%
% Unless required by applicable law or agreed to in writing, software
% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
% License for the specific language governing permissions and limitations under
% the License.
-module(couch_apple_ds_auth).
-include("couch_db.hrl").
-export([apple_ds_authentication_handler/1]).
-define(REQ_TIMEOUT, 30000).
apple_ds_authentication_handler(#httpd{mochi_req = MochiReq} = Req) ->
?LOG_DEBUG("Before get cookie name", []),
CookieName = couch_config:get("apple_application", "auth_cookie_name"),
?LOG_DEBUG("After get cookie name", []),
case MochiReq:get_cookie_value(CookieName) of
undefined ->
?LOG_DEBUG("Redirecting, cookie not found", []),
redirect_for_login(Req);
CookieValue ->
?LOG_DEBUG("Found cookie ~p for Apple DS authentication with value: ~p",
[CookieName, CookieValue]),
validate_cookie(Req, CookieValue)
end.
redirect_for_login(Req) ->
AppIdKey = couch_config:get("apple_application", "app_id_key"),
LoginUrl = couch_config:get("apple_application", "login_url") ++
"?appIdKey=" ++ couch_util:url_encode(AppIdKey),
couch_httpd:send_response(Req, 301, [{"Location", LoginUrl}], <<>>),
Req.
validate_cookie(#httpd{peer = Peer} = Req, CookieValue) ->
Params = [
{"cookie", CookieValue},
{"ip", Peer},
{"appId", couch_config:get("apple_application", "app_id_key")},
{"func", couch_config:get("apple_application", "func")},
{"appAdminPassword",
couch_config:get("apple_application", "app_admin_password")}
],
{ok, ValidateUrl} = validate_url(Params),
case send_validate_req(ValidateUrl) of
{error, Reason} ->
?LOG_ERROR("Error during authentication through Apple DS: ~s",[Reason]),
redirect_for_login(Req);
{ok, _Headers, Body} ->
?LOG_DEBUG("Received body from request to validate URL ~p is: ~p",
[ValidateUrl, Body]),
{ok, Reply} = parse_validation_reply(Body),
case couch_util:get_value("status", Reply) of
"0" ->
Req#httpd{user_ctx = #user_ctx{roles = [<<"_admin">>]}};
"STATUS_SUCCESS" ->
Req#httpd{user_ctx = #user_ctx{roles = [<<"_admin">>]}};
_ ->
redirect_for_login(Req)
end
end.
parse_validation_reply(Body) ->
Lines = re:split(Body, "\r\n|\n", [{return, list}]),
KVs = lists:foldl(
fun(Line, Acc) ->
[K, V] = re:split(Line, "=", [{return, list}]),
[{couch_util:trim(K), couch_util:trim(V)} | Acc]
end,
[], Lines
),
{ok, KVs}.
send_validate_req(Url) ->
case ibrowse:send_req(Url, [], get, [],
[{response_format, list}, {inactivity_timeout, ?REQ_TIMEOUT}]) of
{ok, "200", Headers, Body} ->
{ok, Headers, Body};
{ok, Code, _Headers, _Body} ->
Reason = io_lib:format("received HTTP code ~s from the validation URL",
[Code]),
{error, Reason};
{error, Reason} ->
{error, couch_util:to_list(Reason)}
end.
validate_url(Params) ->
BaseUrl = couch_config:get("apple_application", "validate_url"),
QS = lists:foldl(
fun({_K, undefined}, Acc) ->
Acc;
({K, V}, Acc) ->
[K ++ "=" ++ couch_util:url_encode(V) | Acc]
end,
[], Params
),
{ok, BaseUrl ++ "?" ++ string:join(QS, "&")}.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment