create or replace package body wsgsec is
--
--
c_session_duration_hours constant number := 3;
v_current_user varchar2(30);
--
-- Check_Session: Check that the supplied client ID is valid
-- for the IP address of the client, that the
-- session is still valid, and that the client
-- ID supplied is not null.
--
function check_session( p_client_id in varchar2 ) return boolean
is
l_stored_ip varchar2(30);
l_current_ip varchar2(30);
l_check_ok boolean;
l_expires date;
begin
if p_client_id is not null then
--
-- Get IP address of client
--
l_current_ip := owa_util.get_cgi_env('REMOTE_ADDR');
l_check_ok := true;
--
-- Check wsgsec_sessions table for an existing session
-- with the specified ID and the current IP address
--
begin
select ip_address
, expires
into l_stored_ip
, l_expires
from wsgsec_sessions
where client_id = p_client_id
and ip_address = l_current_ip;
exception when no_data_found then
l_check_ok := false;
l_expires := sysdate;
end;
--
-- Check that the session has not expired
--
if (sysdate > l_expires) then
l_check_ok := false;
end if;
else
--
-- Supplied client ID was null, so return fail.
--
l_check_ok := false;
end if;
--
-- If an invalid session was found (either expired or for
-- another IP address) then delete that session.
--
if not l_check_ok and p_client_id is not null then
dbms_transaction.begin_discrete_transaction;
delete from wsgsec_sessions where client_id = p_client_id;
commit;
end if;
--
return l_check_ok;
end;
--
--
-- Generate_Client_Id: Generate a unique identifier for a new session.
--
function generate_client_id return varchar2
is
l_client_id varchar2(240);
l_is_unique boolean := false;
l_count integer;
begin
--
-- Generate a pseudo random number.
select to_char(to_number( userenv( 'sessionid' ) ) * to_number( to_char( sysdate,'DDDSSSS' ) ) )
into l_client_id
from sys.dual;
--
-- Check that it is unique in the session table. If it is not, increment
-- it until it is.
--
while not l_is_unique loop
begin
select count(*)
into l_count
from wsgsec_sessions
where client_id = l_client_id;
exception when no_data_found then
l_count := 0;
end;
if l_count = 0 then
--
-- The ID does not already exist in session table
--
l_is_unique := true;
else
l_client_id := to_number(l_client_id) + 1;
end if;
end loop;
return l_client_id;
end;
--
--
-- Get_User: Returns user name of current user.
--
function get_user return varchar2
is
begin
return v_current_user;
end;
--
--
-- Get_User_Data: Returns information about a user, specified by
-- p_key. This implementation accepts the key
-- 'PASSWORD' only. Any other key will result in
-- a null string being returned.
--
function get_user_data( p_key in varchar2 ) return varchar2
is
l_client_id varchar2(240);
l_password varchar2(30);
begin
if upper(p_key) = 'PASSWORD' then
--
-- Get the current client ID
--
l_client_id := WSGL.GetClientID;
--
-- Get user's password by joining to user table
--
if l_client_id is not null then
begin
select password
into l_password
from wsgsec_user u
, wsgsec_sessions s
where s.client_id = l_client_id
and u.user_name = s.user_name;
exception when others then
l_password := null;
end;
end if;
end if;
return l_password;
end;
--
--
-- Security_Check: Returns true if the currently logged on user is
-- allowed access to the specified package. If not,
-- will return false. This function will also provide
-- a means for the user to log on.
--
function security_check( p_package_name in varchar2 ) return boolean
is
l_client_id varchar2(240);
l_username varchar2(30);
l_rows integer := 0;
begin
--
-- Get the current client ID
--
l_client_id := WSGL.GetClientID;
if l_client_id is not null then
--
-- Call check_session to ensure current session
-- is valid
--
if check_session( l_client_id ) then
--
-- Get user name
--
begin
select user_name
into v_current_user
from wsgsec_sessions
where client_id = l_client_id;
exception when others then
v_current_user := null;
end;
--
-- Check that the current user has a responsibility
-- that allows it to access the specified package name
--
begin
select count(*)
into l_rows
from wsgsec_userresp ur
, wsgsec_perm pm
where ur.user_name = v_current_user
and pm.package_name = p_package_name
and ur.responsibility_name = pm.responsibility_name;
exception when no_data_found then
l_rows := 0;
end;
else
--
-- No valid session was found, so display a
-- logon form.
--
call_logon_form;
return false;
end if;
--
if l_rows != 0 then
--
-- User is logged on and has permission to access
-- the specified package.
--
return true;
else
--
-- User is logged on but does not have permission
-- to access the specified package
--
show_no_access;
return false;
end if;
else
--
-- No current client ID, so display logon form.
--
call_logon_form;
return false;
end if;
end;
--
--
-- Show_Logon_Form: Renders logon form
--
procedure show_logon_form( p_embedded in boolean )
is
begin
if not p_embedded then
htp.htmlOpen;
htp.headOpen;
htp.title(WSGL.MsgGetText(605,WSGLM.SEC605_LOGON_CAPTION));
htp.headClose;
htp.bodyOpen (cattributes=> 'onLoad="return Logon_OnLoad()"');
end if;
-- Output JavaScript for handling onLoad event for setting
-- the focus to the username field upon invocation.
htp.p ('');
htp.header( 2, WSGL.MsgGetText(601,WSGLM.SEC601_LOGON_REQUIRED) );
htp.header( 4, WSGL.MsgGetText(602,WSGLM.SEC602_USERNAME_PASSWORD) );
htp.formOpen( curl=>'wsgsec.process_logon', ctarget=>'', cattributes => 'NAME="Logonform"' );
htp.tableOpen;
htp.tableRowOpen;
htp.tableData( ''||WSGL.MsgGetText(603,WSGLM.SEC603_USERNAME_PROMPT)||' ');
htp.tableData( htf.formText( cname=>'p_username' ) );
htp.tableRowClose;
htp.tableRowOpen;
htp.tableData( ''||WSGL.MsgGetText(604,WSGLM.SEC604_PASSWORD_PROMPT)||' ');
htp.tableData( htf.formPassword( cname=>'p_password' ) );
htp.tableRowClose;
htp.tableRowOpen;
htp.tableData( htf.formSubmit( cvalue=>WSGL.MsgGetText(605,WSGLM.SEC605_LOGON_CAPTION) ) );
htp.tableRowClose;
htp.tableClose;
htp.formClose;
if not p_embedded then
htp.bodyClose;
htp.htmlClose;
end if;
end;
--
--
-- Process_Logon: Accepts submitted logon form and logs user on. If logon
-- fails then notifies user.
--
procedure process_logon( p_username in varchar2
, p_password in varchar2 )
is
l_client_id varchar2(240);
l_rows integer := 0;
l_success boolean := false;
l_current_ip varchar2(30);
begin
--
-- Check that user exists in user table with the specified
-- username and password. l_rows will be non-zero if this
-- is the case.
--
begin
select count(*)
into l_rows
from wsgsec_user
where user_name = p_username
and password = p_password;
exception when no_data_found then
l_rows := 0;
end;
--
-- Get current client ID
--
l_client_id := WSGL.GetClientID;
--
-- If username/password valid
--
if l_rows != 0 then
--
-- Check that current client ID is valid
--
if l_client_id is not null and check_session( l_client_id ) then
--
-- Update the session table for this client with
-- the new user
--
dbms_transaction.begin_discrete_transaction;
update wsgsec_sessions
set user_name = p_username
where client_id = l_client_id;
commit;
l_success := true;
else
--
-- Current client ID is not valid so create a new one
--
l_client_id := generate_client_id;
--
-- Write to browser as a cookie
--
WSGL.StoreClientID( l_client_id );
--
-- Get current IP address
--
l_current_ip := owa_util.get_cgi_env('REMOTE_ADDR');
--
-- Create new session in session table
--
dbms_transaction.begin_discrete_transaction;
insert into wsgsec_sessions( client_id, user_name, ip_address, expires )
values( l_client_id, p_username, l_current_ip, (sysdate + (c_session_duration_hours / 24)) );
commit;
l_success := true;
end if;
elsif l_client_id is not null then
--
-- Invalid logon so delete the session for the current client.
--
dbms_transaction.begin_discrete_transaction;
delete from wsgsec_sessions where client_id = l_client_id;
commit;
end if;
--
-- Output HTML to indicate success or failure
--
htp.htmlOpen;
if l_success then
htp.bodyOpen;
htp.header(2, WSGL.MsgGetText(606,WSGLM.SEC606_LOGON_SUCCESS));
htp.header(4, WSGL.MsgGetText(607,WSGLM.SEC607_NAVIGATE_BACK));
htp.script( '
' );
htp.script( '
' );
else
htp.bodyOpen (cattributes=> 'onLoad="return Logon_OnLoad()"');
htp.header(2, WSGL.MsgGetText(608,WSGLM.SEC608_INVALID_LOGON));
htp.hr;
show_logon_form( true );
end if;
htp.bodyClose;
htp.htmlClose;
end;
--
--
-- Show_No_Access: Displays message to inform user that they do not
-- have access to the application. Provides a link
-- to the logon form.
--
procedure show_no_access
is
begin
htp.htmlOpen;
htp.headOpen;
htp.title('Access Denied');
htp.headClose;
htp.bodyOpen;
htp.script('
function show_logon() {
frmLogon = open("wsgsec.show_logon_form","winLogon","scrollbars=no,resizable=yes,width=400,height=300");
if (frmLogon.opener == null) {
frmLogon.opener = self;
};
};');
htp.header(2, WSGL.MsgGetText(609,WSGLM.SEC609_ACCESS_DENIED));
htp.header(4, WSGL.MsgGetText(610,WSGLM.SEC610_NO_PERMISSION));
htp.hr;
htp.p('');
htp.p('');
htp.bodyClose;
htp.htmlClose;
end;
--
--
-- Call_Logon_Form: Outputs javascript to popup logon form in new window,
-- or include logon form in current window if javascript
-- is not available.
--
procedure call_logon_form
is
begin
htp.htmlOpen;
htp.bodyOpen;
--
htp.script('
' );
htp.p('');
--
htp.bodyClose;
htp.htmlClose;
end;
--
--
-- Add_Package_Resp: Adds a respondibility to a package, allowing users
-- with that responsibility to access the application.
-- This is called from the generated application
-- installation script if a value is supplied for
-- preference SECRES.
--
procedure add_package_resp( p_package_name in varchar2
, p_responsibility in varchar2 )
is
l_rows integer := 0;
begin
--
-- Determine whether responsibility exists
--
begin
select count(*)
into l_rows
from wsgsec_resp
where responsibility_name = p_responsibility;
exception when no_data_found then
l_rows := 0;
end;
if l_rows = 0 then
--
-- Responsibility does not exist, so create it
--
dbms_transaction.begin_discrete_transaction;
insert into wsgsec_resp( responsibility_name ) values ( p_responsibility );
commit;
end if;
--
-- Add row to wsgsec_perm table to grant package access
-- to the responsibility, if it does not already exist.
--
begin
select count(*)
into l_rows
from wsgsec_perm
where responsibility_name = p_responsibility
and package_name = p_package_name;
exception when no_data_found then
l_rows := 0;
end;
if l_rows = 0 then
dbms_transaction.begin_discrete_transaction;
insert into wsgsec_perm( responsibility_name, package_name )
values( p_responsibility, p_package_name );
commit;
end if;
end;
--
--
-- Logoff: Removes the current user's session, logging them off. Outputs
-- HTML message when complete.
--
procedure logoff
is
l_client_id varchar2(240);
begin
htp.htmlOpen;
htp.headOpen;
htp.title(WSGL.MsgGetText(611,WSGLM.SEC611_LOGGING_OFF));
htp.headClose;
htp.bodyOpen;
--
-- Get current client ID
--
l_client_id := WSGL.GetClientID;
if l_client_id is not null then
--
-- Delete session for this client
--
dbms_transaction.begin_discrete_transaction;
delete from wsgsec_sessions where client_id = l_client_id;
commit;
end if;
htp.header(2, WSGL.MsgGetText(612,WSGLM.SEC612_LOGGED_OFF));
htp.bodyClose;
htp.htmlClose;
end;
--
--
-- Create_User: Creates a user with the specified name and password
--
procedure create_user( p_username in varchar2
, p_password in varchar2 )
is
l_rows integer;
begin
--
-- Determine whether user already exists
--
begin
select count(*)
into l_rows
from wsgsec_user
where user_name = p_username;
exception when no_data_found then
l_rows := 0;
end;
if l_rows = 0 then
--
-- User does not exist, so create new one
--
dbms_transaction.begin_discrete_transaction;
insert into wsgsec_user( user_name, password ) values (p_username, nvl(p_password, p_username));
commit;
else
--
-- User exists, so update password
--
dbms_transaction.begin_discrete_transaction;
update wsgsec_user set password = nvl(p_password, p_username) where user_name = p_username;
commit;
end if;
end;
end wsgsec;
/
show errors