PageRenderTime 65ms CodeModel.GetById 31ms app.highlight 28ms RepoModel.GetById 1ms app.codeStats 1ms

/src/support/z_auth.erl

https://code.google.com/p/zotonic/
Erlang | 171 lines | 111 code | 24 blank | 36 comment | 0 complexity | 1f532009611ed2d49702b0545e97ed79 MD5 | raw file
  1%% @author Marc Worrell <marc@worrell.nl>
  2%% @copyright 2009 Marc Worrell
  3%% Date: 2009-04-24
  4%%
  5%% @doc Handle authentication of zotonic users.  Also shows the logon screen when authentication is required.
  6
  7%% Copyright 2009 Marc Worrell
  8%%
  9%% Licensed under the Apache License, Version 2.0 (the "License");
 10%% you may not use this file except in compliance with the License.
 11%% You may obtain a copy of the License at
 12%% 
 13%%     http://www.apache.org/licenses/LICENSE-2.0
 14%% 
 15%% Unless required by applicable law or agreed to in writing, software
 16%% distributed under the License is distributed on an "AS IS" BASIS,
 17%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 18%% See the License for the specific language governing permissions and
 19%% limitations under the License.
 20
 21-module(z_auth).
 22-author("Marc Worrell <marc@worrell.nl").
 23
 24%% interface functions
 25-export([
 26    is_auth/1,
 27    is_auth_recent/1,
 28    
 29    logon/2,
 30    confirm/2,
 31    logon_pw/3,
 32    logoff/1,
 33    logon_from_session/1,
 34
 35    user_from_page/1,
 36    user_from_session/1,
 37
 38    is_enabled/2
 39]).
 40
 41-define(AUTH_RECENT_TIMEOUT, 600).
 42
 43-include_lib("zotonic.hrl").
 44
 45
 46%% @doc Check if the visitor has been authenticated. Assumes a completely initalized context.
 47%% @spec is_auth(#context{}) -> bool()
 48is_auth(#context{user_id=undefined}) ->
 49    false;
 50is_auth(_) ->
 51    true.
 52
 53is_auth_recent(#context{user_id=undefined}) ->
 54    false;
 55is_auth_recent(#context{}=Context) ->
 56    case z_context:get_session(auth_confirm_timestamp, Context) of
 57        undefined ->
 58            false;
 59        AuthConfirmTimestamp ->
 60            ?DEBUG(AuthConfirmTimestamp),
 61            CurrentTimestamp = z_utils:now(),
 62            AuthConfirmTimestamp + ?AUTH_RECENT_TIMEOUT > CurrentTimestamp
 63    end.
 64
 65%% @doc Logon a username/password combination, checks passwords with m_identity.
 66%% @spec logon_pw(Username, Password, Context) -> {bool(), NewContext}
 67logon_pw(Username, Password, Context) ->
 68    case m_identity:check_username_pw(Username, Password, Context) of
 69        {ok, Id} ->
 70			case logon(Id, Context) of
 71				{ok, Context1} ->
 72                                    Context1;
 73				{error, _Reason} -> {false, Context}
 74			end;
 75        {error, _Reason} -> {false, Context}
 76    end.
 77
 78confirm(UserId, Context) ->
 79    % check if auth_user_id == userId??
 80    case is_enabled(UserId, Context) of
 81        true ->        
 82            Context1 = z_context:set_session(auth_confirm_timestamp, z_utils:now(), Context),
 83            Context2 = z_notifier:foldl(auth_confirm, Context1, Context1),
 84            z_notifier:notify(auth_confirm_done, Context2),
 85            {ok, Context2};
 86        false ->
 87            {error, user_not_enabled}
 88    end.
 89    
 90
 91%% @doc Logon an user whose id we know
 92logon(UserId, Context) ->
 93	case is_enabled(UserId, Context) of
 94		true ->
 95		    Context1 = z_acl:logon(UserId, Context),
 96			Context2 = z_session_manager:rename_session(Context1),
 97		    z_context:set_session(auth_user_id, UserId, Context2),
 98		    z_context:set_session(auth_timestamp, calendar:universal_time(), Context2),
 99		    Context3 = z_notifier:foldl(auth_logon, Context2, Context2),
100		    z_notifier:notify(auth_logon_done, Context3),
101		    {ok, Context3};
102		false ->
103			{error, user_not_enabled}
104	end.
105
106
107%% @doc Forget about the user being logged on.
108%% @spec logoff(Context) -> NewContext
109logoff(Context) ->
110    ContextLogOff = z_notifier:foldl(auth_logoff, Context, Context),
111    z_context:set_session(auth_user_id, none, ContextLogOff),
112    z_notifier:notify(auth_logoff_done, ContextLogOff),
113    z_acl:logoff(ContextLogOff).
114
115%% @doc Return the user_id from the session
116user_from_session(SessionPid) ->
117    z_session:get(auth_user_id, SessionPid).
118
119%% @doc Return the user_id from a page
120user_from_page(PagePid) ->
121    user_from_session(z_session_page:session_pid(PagePid)).
122
123%% @doc Called after z_context:ensure_session. 
124%% Check if the session contains an authenticated user id. 
125%% When found then the user_id of the context is set.
126%% Also checks any automatic logon methods like "remember me" cookies.
127%% @spec logon_from_session(#context{}) -> #context{}
128logon_from_session(Context) ->
129    case z_context:get_session(auth_user_id, Context) of
130        none ->
131        	z_memo:set_userid(undefined),
132            Context;
133        undefined ->
134            % New session, check if some module wants to log on
135        	case z_notifier:first(auth_autologon, Context) of
136        	    undefined -> 
137            	    z_memo:set_userid(undefined),
138        	        z_context:set_session(auth_user_id, none, Context);
139        	    {ok, UserId} ->
140					case logon(UserId, Context) of
141						{ok, ContextLogon} -> 
142	            	    	z_memo:set_userid(UserId),
143							ContextLogon;
144						{error, _Reason} -> 
145							z_memo:set_userid(undefined),
146				        	Context
147					end
148            end;
149        UserId ->
150        	z_memo:set_userid(UserId),
151            z_acl:logon(UserId, Context)
152    end.
153
154
155%% @doc Check if the user is enabled, an user is enabled when the rsc is published and within its publication date range.
156is_enabled(UserId, Context) ->
157	case z_notifier:first({user_is_enabled, UserId}, Context) of
158		undefined ->
159			Acl = m_rsc:get_acl_props(UserId, Context),
160		    case Acl#acl_props.is_published of
161		        false -> 
162		            false;
163		        true ->
164		            Date = calendar:local_time(),
165		            Acl#acl_props.publication_start =< Date andalso Acl#acl_props.publication_end >= Date
166		    end;
167		Other when is_boolean(Other) ->
168			Other
169	end.
170
171