Permalink
Browse files

Reintroduced the SPNEGO/GSSAPI auth support by Mikael Magnusson

git-svn-id: https://erlyaws.svn.sourceforge.net/svnroot/erlyaws/trunk/yaws@1207 9fbdc01b-0d2c-0410-bfb7-fb27d70d8b52
  • Loading branch information...
1 parent 5749449 commit a3f4fdebed12160496bb0b59250c4263c7ecb67a @klacke committed Jan 3, 2008
Showing with 199 additions and 2 deletions.
  1. +2 −2 src/Makefile
  2. +197 −0 src/authmod_gssapi.erl
View
@@ -35,8 +35,8 @@ MODULES=yaws \
yaws_pam \
json jsonrpc yaws_jsonrpc yaws_xmlrpc\
haxe yaws_rpc \
- yaws_soap_srv yaws_soap_lib
-# authmod_gssapi
+ yaws_soap_srv yaws_soap_lib \
+ authmod_gssapi
EBIN_FILES=$(MODULES:%=../ebin/%.$(EMULATOR)) ../ebin/yaws.app
View
@@ -0,0 +1,197 @@
+%%%-------------------------------------------------------------------
+%%% File : authmod_gssapi.erl
+%%% Author : Mikael Magnusson <mikael@skinner.hem.za.org>
+%%% Description : Negotiate authentication module supporting GSSAPI
+%%% and SPNEGO
+%%%
+%%% Created : 17 May 2007 by Mikael Magnusson <mikael@skinner.hem.za.org>
+%%%-------------------------------------------------------------------
+%%%
+%%% Copyright (c) 2007 Mikael Magnusson
+%%% All rights reserved.
+%%%
+%%% Redistribution and use in source and binary forms, with or without
+%%% modification, are permitted provided that the following conditions
+%%% are met:
+%%%
+%%% 1. Redistributions of source code must retain the above copyright
+%%% notice, this list of conditions and the following disclaimer.
+%%%
+%%% 2. Redistributions in binary form must reproduce the above copyright
+%%% notice, this list of conditions and the following disclaimer in the
+%%% documentation and/or other materials provided with the distribution.
+%%%
+%%% 3. Neither the name of the copyright owner nor the names of its
+%%% contributors may be used to endorse or promote products derived from
+%%% this software without specific prior written permission.
+%%%
+%%% THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+%%% ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+%%% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+%%% ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+%%% FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+%%% DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+%%% OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+%%% HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+%%% LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+%%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+%%% SUCH DAMAGE.
+
+
+
+
+%% this code adds support for SPNEGO and GSSAPI negotiation to yaws.
+%% It's compatible with both Linux/Unix and Windows.
+%% Supporting both Kerberos for windows (kfw) and SSPI on Windows.
+
+%% It's implemented as an authmod called authmod_gssapi.
+%% Adding it to start_mod in <server> and authmod in an <auth> tag
+%% activates the module. It expects a Kerberos keytab in <opaque>.
+%% The keytab should contain key(s) for "HTTP/<fqdn>@<REALM>",
+%% where <fqdn> is the fully qualified domain name of the host and <REALM>
+%% the kerberos realm.
+
+%% For example:
+
+%% <server fqdn>
+%% port = 80
+%% listen = 0.0.0.0
+%% docroot = /usr/share/yaws
+%% start_mod = authmod_gssapi
+%% <auth> authmod = authmod_gssapi
+%% dir = /
+%% </auth>
+%% <opaque>
+%% keytab = /etc/yaws/http.keytab
+%% </opaque>
+%% </server>
+
+%% The authmod_gssapi module depends on egssapi
+%% from: http://www.hem.za.org/egssapi/
+
+
+
+
+
+
+-module(authmod_gssapi).
+
+-export([
+ start/1,
+ stop/0,
+ auth/2,
+ out/1
+ ]).
+
+-include("yaws.hrl").
+-include("yaws_api.hrl").
+
+-define(SERVER, ?MODULE).
+-define(SUPERVISOR, yaws_sup).
+
+%%-define(ENABLE_DEBUG, yes).
+
+-ifdef(ENABLE_DEBUG).
+-define(INFO, io:format).
+-define(DEBUG, io:format).
+-else.
+-define(INFO, ignore).
+-define(DEBUG, ignore).
+-endif.
+
+-define(WARNING, io:format).
+-define(ERROR, io:format).
+
+
+start(Sconf) when is_record(Sconf, sconf) ->
+ Opaque = Sconf#sconf.opaque,
+ start_opaque(Opaque);
+
+
+start(Keytab) when is_list(Keytab) ->
+ ChildSpec =
+ {?SERVER,
+ {egssapi, start_link, [{local, ?SERVER}, Keytab]},
+ permanent,
+ 1000,
+ worker,
+ [egssapi, spnego]},
+
+ supervisor:start_child(?SUPERVISOR, ChildSpec).
+
+stop() ->
+ egssapi:stop(?SERVER),
+ supervisor:terminate_child(?SUPERVISOR, ?SERVER),
+ supervisor:delete_child(?SUPERVISOR, ?SERVER).
+
+
+auth(Arg, Auth) when is_record(Arg, arg),
+ is_record(Auth, auth) ->
+
+ H = Arg#arg.headers,
+
+ ?INFO("~p~n", [?MODULE]),
+
+ case H#headers.authorization of
+ undefined ->
+ ?INFO("Request auth~n"),
+ {appmod, ?MODULE};
+ {_, _, "Negotiate " ++ Data} ->
+ ?INFO("Negotiate~n", []),
+ Bin = base64:decode(Data),
+
+ case catch spnego:accept_sec_context(?SERVER, Bin) of
+ {'EXIT', Reason} ->
+ ?ERROR("spnego failed EXIT:~p~n", [Reason]),
+ throw(Reason);
+ {error, Reason} ->
+ ?ERROR("spnego failed error:~p~n", [Reason]),
+ throw(Reason);
+ {ok, {Context, User, Ccname, Resp}} ->
+ ?DEBUG("spnego user ok ~p~n", [User]),
+ spnego:delete_sec_context(Context),
+ {true, {User, Ccname, base64:encode(Resp)}};
+ E ->
+ ?ERROR("spnego error ~p~n", [E]),
+ throw(error)
+ end
+ end.
+
+out(_Arg) ->
+ [{status, 401},
+ {header, ["WWW-Authenticate:", "Negotiate"]},
+ {ehtml,
+ [{html,[],
+ [
+ {body, [],
+ [{h1,[], "401 authentication needed"}
+ ]
+ }
+ ]
+ }
+ ]
+ } ].
+
+
+start_opaque(Opaque) when is_list(Opaque) ->
+ if
+ is_list(Opaque) ->
+ Keytab = get_option("keytab", Opaque),
+ start(Keytab);
+ true ->
+ throw(keytab_not_found)
+ end.
+
+get_option(Name, Options) when is_list(Options) ->
+ case lists:keysearch(Name, 1, Options) of
+ {value, {Name, Value}} ->
+ Value;
+ false ->
+ throw(not_found)
+ end.
+
+-ifndef(ENABLE_DEBUG).
+ignore(_) -> ok.
+ignore(_,_) -> ok.
+-endif.
+

0 comments on commit a3f4fde

Please sign in to comment.