Tuesday, 28 May 2019

Oracle EBS Workflow Mailer Troubleshooting

Oracle Ebusiness Suite (EBS) Workflow Mailer Troubleshooting

Check EBS workflow mailer service current status
========================================
  SQL> select running_processes from apps.fnd_concurrent_queues where concurrent_queue_name = 'WFMLRSVC';


Number of running processes should be greater than 0

Current mailer status
=================
  SQL> select component_status from apps.fnd_svc_components where component_id = (select component_id from apps.fnd_svc_components where component_name = 'Workflow Notification Mailer');

  Possible values:
  RUNNING
  STARTING
  STOPPED_ERROR
  DEACTIVATED_USER
  DEACTIVATED_SYSTEM



Stop notification mailer
===================
SQL>
  declare
       p_retcode number;
       p_errbuf varchar2(100);
       m_mailerid fnd_svc_components.component_id%TYPE;
  begin
       -- Find mailer Id
       -----------------
       select component_id
         into m_mailerid
         from fnd_svc_components
        where component_name = 'Workflow Notification Mailer';
       --------------
       -- Stop Mailer
       --------------
       fnd_svc_component.stop_component(m_mailerid, p_retcode, p_errbuf);
       commit;
  end;
  /




Start notification mailer
===================
SQL>
  declare
       p_retcode number;
       p_errbuf varchar2(100);
       m_mailerid fnd_svc_components.component_id%TYPE;
  begin
       -- Find mailer Id
       -----------------
       select component_id
         into m_mailerid
         from fnd_svc_components
        where component_name = 'Workflow Notification Mailer';
       --------------
       -- Start Mailer
       --------------
       fnd_svc_component.start_component(m_mailerid, p_retcode, p_errbuf);
       commit;
  end;
  /

A workflow notification send event (notification email) can fail at several different points, so monitoring it using one method usually is not going to give you a complete picture.Additionally, you have to keep in mind that the process is dynamic, meaning that as transactions are created into the queues they are also mailed out; so a
count of data is at best only a snapshot of a particular moment in time.

  Here is a more robust script for monitoring the wf_notifications table:
select message_type, mail_status, count(*) from wf_notifications
where status = 'OPEN'
GROUP BY MESSAGE_TYPE, MAIL_STATUS
messages in 'FAILED' status can be resent using the concurrent request 'resend failed workflow notificaitons'
messages which are OPEN but where mail_status is null have a missing email address for the recipient, but the notification preference is 'send me mail'

 Some messages like alerts don't get a record in wf_notifications table so you have to watch the WF_NOTIFICATION_OUT queue.

select corr_id, retry_count, msg_state, count(*)
from applsys.aq$wf_notification_out
group by corr_id, msg_state, retry_count
order by count(*) desc;
Messages with a high retry count have been cycling through the queue and are not passed to smtp service.Messages which are 'expired' can be rebuilt using the wfntfqup.sql

SQL to collect all the info except IMAP account password.
===============================================

select p.parameter_id,
p.parameter_name,
v.parameter_value value
from fnd_svc_comp_param_vals_v v,
fnd_svc_comp_params_b p,
fnd_svc_components c
where c.component_type = ‘WF_MAILER’
and v.component_id = c.component_id
and v.parameter_id = p.parameter_id
and p.parameter_name in (‘OUTBOUND_SERVER’, ‘INBOUND_SERVER’,
‘ACCOUNT’, ‘FROM’, ‘NODENAME’, ‘REPLYTO’,'DISCARD’ ,’PROCESS’,'INBOX’)

How to Enable the Oracle EBS Workflow Logging:
=========================================

From Self Service > Select “Workflow Manager” under “Oracle Applications Manager” > Click “Notification Mailers” > Service Components (Service Components: <SID>) >
b. Click “Workflow Mailer Service” under “Container” Column.
e. From “Service Instances for Generic Service Component Container:<SID>”page, click “Pull Down” button from the Start All/ Stop All.
f . Select Stop All > Go.
g. We conformed that for the Services to read Actual 0 Target 0 and Deactivated.
h. Restart the mailer services using the “Start All” button.
I. We run the following SQL to make sure service are stopped.
SELECT component_name, component_status, component_status_info
FROM fnd_svc_components_v
WHERE component_name like ‘Workflow%’;
Enable the Statement logging in Workflow Mailer.
Log files are created  $APPLCSF/$APPLLOG/FNDCPGSC*.txt i.e. the log file for the Active process for Workflow Mailer Service and Agent Listener services.
To retrieve the last 2 log files for Workflow Mailer and Agent Listener services, run the following command:
ls -lt $APPLCSF/$APPLLOG/FNDCPGSC*.txt

How does workflow Notification Mailer IMAP (Inbound Processing) Works:
============================================================
This is the inbound flow:

1. Approver sends email response which is directed to the value defined in Replyto address.
a. This address has been setup by the customer’s mail administrator to route incoming mail to the IMAP Inbox folder.
2. The Workflow Inbound Agent Listener picks up the message. Only messages which are in ‘unread’ state are evaluated; the rest of the messages in the inbox are ignored.

3. The message is scanned to see if it matches entries in the TAG file . Mail tags are defined in the OAM mailer configuration pages and these list strings of text and actions to take if those strings are encountered. An example of this are ‘Out of Office’ replies. If the string of the message matches a mail tag and the action is ‘Ignore’ then nothing else will happen.

4. The message is then scanned for the presence of a Notification Id (NID). This NID is matched against valid NID for the mailer node.

5. If valid NID is not detected, (and there is no matching TAG file entry) then the message is placed into the DISCARD folder.

6. If a valid NID is detected the listener raises a subscription to the WF_NOTIFICATION_IN queue and places the mail message in the Processed folder.

7. From this point on the message is handled by the product workflow (like PO APPROVAL) . An event created by that group will monitor the WF_NOTIFICATION_IN queue and will trigger the rest of the approval workflow.

Steps/events for Oracle Workflow Notification Outbound Processing(eMail from Oracle Applications Workflow to Users)
=================================================
1.When workflow Engine determines that a notification message must be sent, it raises an event in BES (Business Event System) oracle.apps.wf.notifications.send
Event is raised with Notification ID (NID) as event key

2. There is seeded subscription to this Event

3. Event is placed on WF_DEFERRED agent

4.Event is dequeued from WF_DEFERRED and subscription is processed

5. Subscription places event message to WF_NOTIFICATION_OUT agent.

6.Notification Mailer dequeues message from WF_NOTIFICATION_OUT agent and
6.1convert XML representation of notification into MIME encoded message (Multi-purpose Internet Mail Extensions) and
6.2 Send message by SMTP (Simple Mail Transfer Protocol) to intended user (IfTest Address/Override Address is set then email is sent to Test Address

E-Mail Notification is sent if all below conditions are truea) Notification status is OPEN or CANCELED   and
b) Notification mail_status is MAIL or INVALID  and
c) Recipient Role has a valid e-mail address and Notification Preference is in the format MAIL%
d) Workflow Deferred Agent Listener is running
e) Workflow Notification Mailer is running

To check a) & b) run below query
SELECT status, mail_status  FROM wf_notifications WHERE notification_id = ‘&NID’;

mail_status >> SENT means mail has gone out of mailer to user

To check c) run below query
SELECT email_address, nvl(WF_PREF.get_pref(name, ‘MAILTYPE’),notification_preference)
FROM wf_roles
WHERE name = upper(‘&recipient_role’);

To check d) & e) Use OAM (Oracle Application Manager)

How to purge e-mail notifications from the Workflow queue
================================================
Sometimes Due to large number of e-mail notifications to accumulated in the queue Workflow mailer will not start,To fix this issue we need purge the notifications from the Workflow queue.


The below outlines the steps, Please take proper backup before performing the below.

1) You need to update the notifications you do not want sent, in the WF_NOTIFICATIONS table.

2) Check the WF_NOTIFICATIONS table as below. Records where status = ‘OPEN’ and mail_status = ‘MAIL’ are notifications that will have an e-mail notification sent.

SQL> select notification_id,status,mail_status,begin_date from WF_NOTIFICATIONS where status = ‘OPEN’ and mail_status = ‘MAIL’;

3) This should show you which notifications are waiting to be e-mailed.

4) To update a notification so that it will not get e-mailed. Set the MAIL_STATUS = ‘SENT’. The mailer will think the e-mail has already been sent and it will not send it again.

SQL> update WF_NOTIFICATIONS set mail_status = ‘SENT’ where mail_status = ‘MAIL’;

-> This will update all notifications waiting to be sent by the mailer.

5) Then run the script wfntfqup.sql to purge the WF_NOTIFICATION_OUT queue and rebuild it with data currently in the WF_NOTIFICATIONS table. This is what purges all notifications waiting in the queue to be sent.Only the ones where mail_status = ‘MAIL’ and status = ‘OPEN’ will be placed in the WF_NOTIFICATION_OUT queue and sent by the mailer.

SQL>sqlplus apps/apps_pwd @$FND_TOP/patch/115/sql/wfntfqup APPS APPS_PWD APPLSYS

6) Now you can start your WF Containers and then Mailer


Workflow Mailer Debugging Script for Debugging Emails issues
====================================================
This article contains various Workflow and Business Event debugging scripts.

--Checking workflow Components status whether are they running or stopped.
select component_type, component_name, Component_status,COMPONENT_STATUS_INFO Error
from fnd_svc_components
where component_type like 'WF%'
order by 1 desc,2,3;


Query to get the log file of active workflow mailer and workflow agent listener Container
=====================================================================
--Note All Workflow Agent Components logs will stored in single file i.e. container log file.
select fl.meaning,fcp.process_status_code, decode(fcq.concurrent_queue_name,'WFMLRSVC', 'mailer container',
'WFALSNRSVC','listener container',fcq.concurrent_queue_name),
fcp.concurrent_process_id,os_process_id, fcp.logfile_name
from fnd_concurrent_queues fcq, fnd_concurrent_processes fcp , fnd_lookups fl
where fcq.concurrent_queue_id=fcp.concurrent_queue_id and fcp.process_status_code='A'
and fl.lookup_type='CP_PROCESS_STATUS_CODE' and fl.lookup_code=fcp.process_status_code
and concurrent_queue_name in('WFMLRSVC','WFALSNRSVC')
order by fcp.logfile_name;


Linux Shell script Command to get outbound error in Mailergrep -i '^\[[A-Za-z].*\(in\|out\).*boundThreadGroup.*\(UNEXPECTED\|ERROR\).*exception.*' <logfilename> | tail -10 ;
--Note: All Mailer log files starts with name FNDCPGSC prefix

Linux Shell script Command to get inbound processing error in Mailer grep -i '^\[[A-Za-z].*.*inboundThreadGroup.*\(UNEXPECTED\|ERROR\).*exception.*' <logfilename> | tail -10 ;



Query to Check Workflow Mailer Backlog:
==================================
 --State=Ready implies that emails are not being sent & Waiting mailer to send emails

select tab.msg_state, count(*) from applsys.aq$wf_notification_out tab group by tab.msg_state ;


Check any particular Alert Message email has be pending by Mailer
select decode(wno.state,
0, '0 = Pending in mailer queue',
1, '1 = Pending in mailer queue',
2, '2 = Sent by mailer on '||to_char(DEQ_TIME),
3, '3 = Exception', 4,'4 = Wait', to_char(state)) State,
to_char(DEQ_TIME),
wno.user_data.TEXT_VC
from wf_notification_out wno
where corrid='APPS:ALR'
and upper(wno.user_data.TEXT_VC) like '%<Subject of Alert Email>%';


Check The Workflow notification has been sent or not
============================================
select mail_status, status from wf_notifications where notification_id=<notification_id>
--If mail_status is MAIL , it means the email delivery is pending for workflow mailer to send the notification
--If mail_status is SENT, its means mailer has sent email
--If mail_status is Null & status is OPEN, its means that no need to send email as notification preference of user is "Don't send email"
--Notification preference of user can be set by user by logging in application + click on preference + the notification preference


Check Whether workflow background Engine is working for given workflow or not in last 2 days
=====================================================================
-- Note: Workflow Deferred activities are run by workflow background engine.
select a.argument1,a.phase_code, a.status_code ,a.actual_start_date,a.* from fnd_concurrent_requests a
where CONCURRENT_PROGRAM_ID =
(select concurrent_program_id from fnd_concurrent_programs where
CONCURRENT_PROGRAM_NAME='FNDWFBG')
and last_update_Date>sysdate-2 and argument1='<Workflow Item Type>'
order by last_update_date desc

Check whether any business event is pending to process
===============================================
i.e. Query to get event status & parameters value of particular event in wf_deferred table.
select wd.user_Data.event_name,wd.user_Data.event_key,
rank() over ( partition by wd.user_Data.event_name, wd.user_Data.event_key order by n.name) as serial_no,
n.NAME Parameter_name, N.value Parameter_value ,
decode(state, 0, '0 = Ready', 1, '1 = Delayed', 2, '2 = Retained',
3, '3 = Exception', 4,'4 = Wait', to_char(state)) state,
wd.user_Data.SEND_DATE,
wd.user_Data.ERROR_MESSAGE,
wd.user_Data.ERROR_STACK,
wd.msgid,wd.delay
from WF_DEFERRED wd , TABLE(wd.user_Data.PARAMETER_LIST) n
where lower(wd.user_data.event_name)='<event Name >'
order by wd.user_Data.event_name, wd.user_Data.event_key, n.name



When the workflow mailer is either disabled or the mail server restricts its access to the workflow mailer, all the workflow notifications will retry and upto the limit set at the workflow mailer configuration and later all the notifications will be failed. This will result in 2 things at Application level

i) MAIL_STATUS column of the WF_NOTIFICATIONS set to FAILED.

ii) After a series of failure notifications the Notification Style for the respected User will be set as Disabled and a corresponding user details are sent to SYSADMIN.

A similar issue araised in one of the client and the many of the users notification style has been set to Disabled.

Solution:

To overcome the above issue, initially fix the workflow mailer issue and later need to change the Notification Preference at Workflow Administrator to "HTML with Attachments" (or any other as per the client's requirement).

But sometime this setting won't be affected to all the users whose Preference is set to Disabled. To overcome this situation:

i) Backup the following tables:

CREATE FND_USER_PREFERENCES_BAK as select * from FND_USER_PREFERENCES;
CREATE WF_LOCAL_ROLES_BAK as select * from WF_LOCAL_ROLES;

ii) To set the mail preference for all the users execute the following:

update wf_local_roles
set notification_preference='<wished_preference>'
where orig_system in ('FND_USR','PER');

update fnd_user_preferences
set preference_value='<wished_preference>'
where preference_name='MAILTYPE'
and module_name='WF'
and user_name <> '-WF_DEFAULT-';

iii) To update the mail preference of the users only whose preference is set to "FAILED", execute the below steps:

 update wf_local_roles
set notification_preference='<wished_preference>'
where orig_system in ('FND_USR','PER')
and name in
(select user_name
from fnd_user_preferences
where preference_name='MAILTYPE'
and module_name='WF'
and preference_value='DISABLED');

update fnd_user_preferences
set preference_value='<wished_preference>'
where preference_name='MAILTYPE'
and module_name='WF'
and preference_value='DISABLED';

Possible values for <wished_preference> are:
QUERY (corresponds to preference value "Do not send me mail")
MAILTEXT (corresponds to preference value "Plain text mail")
MAILATTH (corresponds to preference value "Plain text mail with HTML attachments")
MAILHTML (corresponds to preference value "HTML mail with attachments")
MAILHTM2 (corresponds to preference value "HTML mail")
SUMMARY (corresponds to preference value "Plain text summary mail")
SUMHTML (corresponds to preference value "HTML summary mail")
DISABLED (corresponds to preference value "Disabled")

iii) To Resend all the failed notifications again to the respected users run the following concurrent program as SYSADMIN, with the relevant parameters.

Retry Error Workflow Activities


Happy Learning!

Friday, 1 March 2019

Enforce Password Complexity for users in Oracle Database 11g/12c

Enforce Password Complexity for users in Oracle Database 11g/12c

create or replace function     ora_string_distance

(s varchar2,

 t varchar2)

return integer is

   s_len    integer := nvl (length(s), 0);

   t_len    integer := nvl (length(t), 0);

   type arr_type is table of number index by binary_integer;

   d_col    arr_type ;

   dist     integer := 0;

begin

   if s_len = 0 then

      dist := t_len;

   elsif t_len = 0 then

      dist := s_len;

   -- Bug 18237713 : If source or target length exceeds max DB password length

   -- that is 128 bytes, then raise exception.

   elsif t_len > 128 or s_len > 128 then

     raise_application_error(-20027,'Password length more than 128 bytes');

   elsif s = t then

     return(0);

   else

      for j in 1 .. (t_len+1) * (s_len+1) - 1 loop

          d_col(j) := 0 ;

      end loop;

      for i in 0 .. s_len loop

          d_col(i) := i;

      end loop;

      for j IN 1 .. t_len loop

          d_col(j * (s_len + 1)) := j;

      end loop;



      for i in 1.. s_len loop

        for j IN 1 .. t_len loop

          if substr(s, i, 1) = substr(t, j, 1)

          then

             d_col(j * (s_len + 1) + i) := d_col((j-1) * (s_len+1) + i-1) ;

          else

             d_col(j * (s_len + 1) + i) := LEAST (

                       d_col( j * (s_len+1) + (i-1)) + 1,      -- Deletion

                       d_col((j-1) * (s_len+1) + i) + 1,       -- Insertion

                       d_col((j-1) * (s_len+1) + i-1) + 1 ) ;  -- Substitution

          end if ;

        end loop;

      end loop;

      dist :=  d_col(t_len * (s_len+1) + s_len);

   end if;



   return (dist);

end;





create or replace function     ora_complexity_check

(password varchar2,

 chars integer := null,

 letter integer := null,

 upper integer := null,

 lower integer := null,

 digit integer := null,

 special integer := null)

return boolean is

   digit_array varchar2(10) := '0123456789';

   alpha_array varchar2(26) := 'abcdefghijklmnopqrstuvwxyz';

   cnt_letter integer := 0;

   cnt_upper integer := 0;

   cnt_lower integer := 0;

   cnt_digit integer := 0;

   cnt_special integer := 0;

   delimiter boolean := false;

   len integer := nvl (length(password), 0);

   i integer ;

   ch char(1);

begin

   -- Check that the password length does not exceed 2 * (max DB pwd len)

   -- The maximum length of any DB User password is 128 bytes.

   -- This limit improves the performance of the Edit Distance calculation

   -- between old and new passwords.

   if len > 256 then

      raise_application_error(-20020, 'Password length more than 256 characters');

   end if;



   -- Classify each character in the password.

   for i in 1..len loop

      ch := substr(password, i, 1);

      if ch = '"' then

         delimiter := true;

      elsif instr(digit_array, ch) > 0 then

         cnt_digit := cnt_digit + 1;

      elsif instr(alpha_array, nls_lower(ch)) > 0 then

         cnt_letter := cnt_letter + 1;

         if ch = nls_lower(ch) then

            cnt_lower := cnt_lower + 1;

         else

            cnt_upper := cnt_upper + 1;

         end if;

      else

         cnt_special := cnt_special + 1;

      end if;

   end loop;



   if delimiter = true then

      raise_application_error(-20012, 'password must NOT contain a '

                               || 'double-quotation mark which is '

                               || 'reserved as a password delimiter');

   end if;

   if chars is not null and len < chars then

      raise_application_error(-20001, 'Password length less than ' ||

                              chars);

   end if;



   if letter is not null and cnt_letter < letter then

      raise_application_error(-20022, 'Password must contain at least ' ||

                                      letter || ' letter(s)');

   end if;

   if upper is not null and cnt_upper < upper then

      raise_application_error(-20023, 'Password must contain at least ' ||

                                      upper || ' uppercase character(s)');

   end if;

   if lower is not null and cnt_lower < lower then

      raise_application_error(-20024, 'Password must contain at least ' ||

                                      lower || ' lowercase character(s)');

   end if;

   if digit is not null and cnt_digit < digit then

      raise_application_error(-20025, 'Password must contain at least ' ||

                                      digit || ' digit(s)');

   end if;

   if special is not null and cnt_special < special then

      raise_application_error(-20026, 'Password must contain at least ' ||

                                      special || ' special character(s)');

   end if;



   return(true);

end;









create or replace FUNCTION ora12c_verify_function14

(username varchar2,

 password varchar2,

 old_password varchar2)

RETURN boolean IS

   differ integer;

   pw_lower varchar2(256);

   db_name varchar2(40);

   i integer;

   simple_password varchar2(10);

   reverse_user varchar2(32);

BEGIN

   IF NOT ora_complexity_check(password, chars => 14, UPPER => 2, LOWER => 2,

                           digit => 2, special => 2) THEN

      RETURN(FALSE);

   END IF;



   -- Check if the password contains the username

   pw_lower := NLS_LOWER(password);

   IF instr(pw_lower, NLS_LOWER(username)) > 0 THEN

     raise_application_error(-20002, 'Password contains the username');

   END IF;



   -- Check if the password contains the username reversed

   reverse_user := '';

   FOR i in REVERSE 1..length(username) LOOP

     reverse_user := reverse_user || substr(username, i, 1);

   END LOOP;

   IF instr(pw_lower, NLS_LOWER(reverse_user)) > 0 THEN

     raise_application_error(-20003, 'Password contains the username ' ||

                                     'reversed');

   END IF;



   -- Check if the password contains the server name

   select name into db_name from sys.v$database;

   IF instr(pw_lower, NLS_LOWER(db_name)) > 0 THEN

      raise_application_error(-20004, 'Password contains the server name');

   END IF;



   -- Check if the password contains 'oracle'

   IF instr(pw_lower, 'oracle') > 0 THEN

        raise_application_error(-20006, 'Password too simple');

   END IF;



   -- Check if the password contains ' company'

   IF instr(pw_lower, ' company') > 0 THEN

        raise_application_error(-20006, 'Password too simple');

   END IF;



 -- Check if the password contains 'password'

   IF instr(pw_lower, 'password') > 0 THEN

        raise_application_error(-20006, 'Password too simple');

   END IF;



    -- Check if the password is too simple

   IF instr(pw_lower, 'abc') > 0 THEN

        raise_application_error(-20006, 'Password too simple');

   END IF;



    IF instr(pw_lower, 'xyz') > 0 THEN

        raise_application_error(-20006, 'Password too simple');

   END IF;



   IF instr(pw_lower, '123') > 0 THEN

        raise_application_error(-20006, 'Password too simple');

   END IF;



   IF instr(pw_lower, '&') > 0 THEN

        raise_application_error(-20006, 'Password must not contain & ');

   END IF;



   IF instr(pw_lower, '@') > 0 THEN

        raise_application_error(-20006, 'Password must not contain @ ');

   END IF;





      -- Check if the password is too simple. A dictionary of words may be

   -- maintained and a check may be made so as not to allow the words

   -- that are too simple for the password.

   IF pw_lower IN ('hello123','welcome1','database1', 'account1', 'user1234',

                              'password1', 'oracle123', 'computer1',

                              'abcdefg1', 'change_on_install') THEN

      raise_application_error(-20006, 'Password too simple');

   END IF;



   -- Check if the password differs from the previous password by at least

   -- 3 characters

   IF old_password IS NOT NULL THEN

     differ := ora_string_distance(old_password, password);

     IF differ < 3 THEN

        raise_application_error(-20010, 'Password should differ from the '

                                || 'old password by at least 3 characters');

     END IF;

   END IF ;



   RETURN(TRUE);

END;





create or replace FUNCTION ORA12C_VERIFY_FUNCTION8

(username varchar2,

 password varchar2,

 old_password varchar2)

RETURN boolean IS

   differ integer;

   pw_lower varchar2(256);

   db_name varchar2(40);

   i integer;

   simple_password varchar2(10);

   reverse_user varchar2(32);

BEGIN

   IF NOT ora_complexity_check(password, chars => 8, UPPER => 1, LOWER => 1,

                           digit => 1, special => 1) THEN

      RETURN(FALSE);

   END IF;



   -- Check if the password contains the username

   pw_lower := NLS_LOWER(password);

   IF instr(pw_lower, NLS_LOWER(username)) > 0 THEN

     raise_application_error(-20002, 'Password contains the username');

   END IF;



   -- Check if the password contains the username reversed

   reverse_user := '';

   FOR i in REVERSE 1..length(username) LOOP

     reverse_user := reverse_user || substr(username, i, 1);

   END LOOP;

   IF instr(pw_lower, NLS_LOWER(reverse_user)) > 0 THEN

     raise_application_error(-20003, 'Password contains the username ' ||

                                     'reversed');

   END IF;



   -- Check if the password contains the server name

   select name into db_name from sys.v$database;

   IF instr(pw_lower, NLS_LOWER(db_name)) > 0 THEN

      raise_application_error(-20004, 'Password contains the server name');

   END IF;



   -- Check if the password contains 'oracle'

   IF instr(pw_lower, 'oracle') > 0 THEN

        raise_application_error(-20006, 'Password too simple');

   END IF;



   -- Check if the password contains ' company'

   IF instr(pw_lower, ' company') > 0 THEN

        raise_application_error(-20006, 'Password too simple');

   END IF;



-- Check if the password contains 'password'

   IF instr(pw_lower, 'password') > 0 THEN

        raise_application_error(-20006, 'Password too simple');

   END IF;



    -- Check if the password is too simple

   IF instr(pw_lower, 'abc') > 0 THEN

        raise_application_error(-20006, 'Password too simple');

   END IF;



    IF instr(pw_lower, 'xyz') > 0 THEN

        raise_application_error(-20006, 'Password too simple');

   END IF;



   IF instr(pw_lower, '123') > 0 THEN

        raise_application_error(-20006, 'Password too simple');

   END IF;



   IF instr(pw_lower, '&') > 0 THEN

        raise_application_error(-20006, 'Password must not contain & ');

   END IF;



   IF instr(pw_lower, '@') > 0 THEN

        raise_application_error(-20006, 'Password must not contain @ ');

   END IF;





      -- Check if the password is too simple. A dictionary of words may be

   -- maintained and a check may be made so as not to allow the words

   -- that are too simple for the password.

   IF pw_lower IN ('hello123','welcome1','database1', 'account1', 'user1234',

                              'password1', 'oracle123', 'computer1',

                              'abcdefg1', 'change_on_install') THEN

      raise_application_error(-20006, 'Password too simple');

   END IF;



   -- Check if the password differs from the previous password by at least

   -- 3 characters

   IF old_password IS NOT NULL THEN

     differ := ora_string_distance(old_password, password);

     IF differ < 3 THEN

        raise_application_error(-20010, 'Password should differ from the '

                                || 'old password by at least 3 characters');

     END IF;

   END IF ;



   RETURN(TRUE);

END;

Wednesday, 2 January 2019

Oracle Database Configuration Assistant DBCA - Silent Mode

Oracle DBCA Silent Mode 

This article demonstrates how to create a new database using the Database Configuration Assistant (DBCA) in silent mode.

Response File

Response files provide all the answers to the questions normally asked by the Database Configuration Assistant (DBCA). You can find a sample DBCA response file under the ORACLE_HOME ($ORACLE_HOME/assistants/dbca/dbca.rsp). 

1. Copy source RDBMS software:
1.1 On the source database server:

Copy the source oracle database home
cd /u01/app/oracle/product
Example:
tar -cvzf /scratch/db_source/OH.tar.gz 11.2.0.4

1.2 On the target database server:

Example:
cd /u02/app/oracle/product
 tar -xvzf /scratch/db_source/OH.tar.gz

2. Clone the Target Oracle home:
cd $ORACLE_HOME/clone/bin
 perl clone.pl ORACLE_HOME="<target_home>" ORACLE_HOME_NAME="<unique_home_name>" ORACLE_BASE="<path_for_ORACLE_BASE>" OSDBA_GROUP=<OSDBA_privileged_group> OSOPER_GROUP=<OSOPER_privileged_group>
Example:
perl clone.pl ORACLE_HOME="/u02/app/oracle/product/11.2.0.4/test_db" ORACLE_HOME_NAME="test_db" ORACLE_BASE="/u02/app/oracle" OSDBA_GROUP=dba OSOPER_GROUP=oinstall

3. DBCA in Silent  Mode:
Edit the response file(.rsp)  as per the Target database:
Set the below parameters specific to target database.
GDBNAME
SID
SYSPASSWORD
SYSTEMPASSWORD
DATAFILEDESTINATION
RECOVERYAREADESTINATION
STORAGETYPE
DISKGROUPNAME
RECOVERYGROUPNAME
CHARACTERSET
NATIONALCHARACTERSET
MEMORYPERCENTAGE
Below is an example of database creation using dbca silent install mode for db_source database.
Example:
[oracle@exadatahost- bin]$ ./dbca -silent -responseFile /u02/app/oracle/product/11.2.0.4/test_db/assistants/dbca/dbca_test_db.rsp
Copying database files
1% complete
3% complete
10% complete
17% complete
24% complete
35% complete
Creating and starting Oracle instance
37% complete
42% complete
47% complete
52% complete
53% complete
56% complete
58% complete
Registering database with Oracle Restart
64% complete
Completing Database Creation
68% complete
71% complete
75% complete
76% complete
77% complete
78% complete
79% complete
80% complete
90% complete
100% complete
Look at the log file "/u02/app/oracle/cfgtoollogs/dbca/test_db/test_db.log" for further details.

4. Set Init Parameters in target :

Compare init parameters in source database  and update them in target database.

Tuesday, 18 December 2018

Weblogic server takes long time to start. Performance tuning of Weblogic server startup.


Weblogic server takes long time to start. Performance tuning of Weblogic server startup.

Cause:

It is observed on some Linux boxes that WebLogic server startup takes several minutes and hangs for a while. Similar behavior happens during the domain creation, when the security information gets populated.

It has also been observed WLS Admin Console slowness due to low entropy.
Linux has two devices to provide random data at any time: /dev/random and /dev/urandom. Both ways should be secure enough to use them in generating PGP keys, ssh challenges, and other applications where secure random numbers are required. Starting on kernel 2.6, default entropy is 4096 bits and problem arises when the entropy available on the system is minimum (around 100 bits or less).
The main difference between those two devices is that /dev/random runs out of random bits and makes you wait for more to be accumulated. Note that on some systems, it can block for a long time waiting for new user-generated entropy to be entered into the system.

In terms of the outcome, /dev/random is categorized as a high quality entropy device if we compare it with /dev/urandom. The latter uses the entropy pool as long as it is available, but falls back on pseudo random numeric algorithms when depleted.

Why a system could be running out of entropy?
You have to consider that an Operating System performs cryptographic operations frequently (on ssh challenges, https connections, etc.) so the /dev/random pool gets consumed quite quickly. OS also expects to feed that pool with I/O operations coming from disk, network, mouse or keyboard but that situation does not happen as quickly. This is a common pattern on virtualized environments or headless boxes.
Is important to mention that Java uses /dev/random by default as entropy generator device.
How to verify if you are encountering this issue?
  1. Check the default system entropy.
$ cat /proc/sys/kernel/random/poolsize
4096
  1. Check the available entropy.
$ cat /proc/sys/kernel/random/entropy_avail
125
On previous example, entropy is too low.
  1. Monitor the current entropy of the system by using the following command:
$ for i in $(seq 500); do cat /proc/sys/kernel/random/entropy_avail ; sleep 5; done
  1. Start a WebLogic server instance. You should see that entropy decreases or stalls.


Solution:
a) WebLogic Server Scope
i.   Edit the Weblogic startup script ($DOMAIN_HOME/bin/startWebLogic.sh)
ii.  Add the following to the JAVA_OPTIONS variable: -Djava.security.egd=file:/dev/./urandom
iii. Save the file.
iv. Set the domain environment. ($DOMAIN_HOME/bin/setDomainEnv.sh)
v.  Start WebLogic instances.
b) JDK Scope

i.   Edit the Java Security Properties file ($JAVA_HOME/jre/lib/security/java.security)
ii.  The securerandom.source property specifies the source of seed data for secure random. If that property points to /dev/random, set it as one of the options listed below.
securerandom.source=file:/dev/./urandom
securerandom.source=file:/dev/urandom
iii.  Save changes and start the WebLogic Server instances.

Temporary solution :
i. Override the JAVA_OPTIONS environment variable before starting WebLogic Server via shell scripts.
$ export JAVA_OPTIONS="${JAVA_OPTIONS} -Djava.security.egd=file:/dev/./urandom"
ii. Start WebLogic instances.




Happy Learning!

Weblogic Not Starting with Error: JPS-06514: Opening of file based keystore failed

Recently, I encountered an issue where the Weblogic Admin server did not start due to an error  JPS-06514: Opening of file based keystore failed

Error Message:
<Error> <Security> <BEA-090892> <The loading of OPSS java security policy provider failed due to exception, see the exception stack trace or the server log file for root cause. If still see no obvious cause, enable the debug flag -Djava.security.debug=jpspolicy to get more information. Error message: JPS-06514: Opening of file based keystore failed.>
 <Critical> <WebLogicServer> <BEA-000386> <Server subsystem failed. Reason: weblogic.security.SecurityInitializationException: The loading of OPSS java security policy provider failed due to exception, see the exception stack trace or the server log file for root cause. If still see no obvious cause, enable the debug flag -Djava.security.debug=jpspolicy to get more information. Error message: JPS-06514: Opening of file based keystore failed.
weblogic.security.SecurityInitializationException: The loading of OPSS java security policy provider failed due to exception, see the exception stack trace or the server log file for root cause. If still see no obvious cause, enable the debug flag -Djava.security.debug=jpspolicy to get more information. Error message: JPS-06514: Opening of file based keystore failed.
        at weblogic.security.service.CommonSecurityServiceManagerDelegateImpl.loadOPSSPolicy(CommonSecurityServiceManagerDelegateImpl.java:1402)
        at weblogic.security.service.CommonSecurityServiceManagerDelegateImpl.initialize(CommonSecurityServiceManagerDelegateImpl.java:1022)
        at weblogic.security.service.SecurityServiceManager.initialize(SecurityServiceManager.java:888)
        at weblogic.security.SecurityService.start(SecurityService.java:141)
        at weblogic.t3.srvr.SubsystemRequest.run(SubsystemRequest.java:64)
        Truncated. see log file for complete stacktrace
Caused By: oracle.security.jps.JpsRuntimeException: JPS-06514: Opening of file based keystore failed.
        at oracle.security.jps.internal.policystore.PolicyDelegationController.<init>(PolicyDelegationController.java:190)
        at oracle.security.jps.internal.policystore.TenantJavaPolicyProvider.<init>(TenantJavaPolicyProvider.java:161)
        at oracle.security.jps.internal.policystore.JavaPolicyProvider.<init>(JavaPolicyProvider.java:306)
        at oracle.security.jps.internal.policystore.JavaPolicyProvider.<init>(JavaPolicyProvider.java:279)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        Truncated. see log file for complete stacktrace
Caused By: oracle.security.jps.JpsException: JPS-06514: Opening of file based keystore failed.
        at oracle.security.jps.internal.policystore.PolicyUtil.getDefaultPDPService(PolicyUtil.java:3180)
        at oracle.security.jps.internal.policystore.PolicyUtil.getPDPService(PolicyUtil.java:3480)
        at oracle.security.jps.internal.policystore.PolicyUtil.getPDPService(PolicyUtil.java:3466)
        at oracle.security.jps.internal.policystore.PolicyDelegationController.<init>(PolicyDelegationController.java:188)
        at oracle.security.jps.internal.policystore.TenantJavaPolicyProvider.<init>(TenantJavaPolicyProvider.java:161)
        Truncated. see log file for complete stacktrace
Caused By: oracle.security.jps.service.keystore.KeyStoreServiceException: JPS-06514: Opening of file based keystore failed.
        at oracle.security.jps.internal.keystore.file.FileKeyStoreManager.openKeyStore(FileKeyStoreManager.java:458)
        at oracle.security.jps.internal.keystore.file.FileKeyStoreManager.openKeyStore(FileKeyStoreManager.java:392)
        at oracle.security.jps.internal.keystore.file.FileKeyStoreServiceImpl.doInit(FileKeyStoreServiceImpl.java:128)
        at oracle.security.jps.internal.keystore.file.FileKeyStoreServiceImpl.start(FileKeyStoreServiceImpl.java:901)
        at oracle.security.jps.internal.keystore.FarmKeyStoreServiceImpl.initialize(FarmKeyStoreServiceImpl.java:148)
        Truncated. see log file for complete stacktrace
Caused By: oracle.security.jps.service.keystore.KeyStoreServiceException: JPS-06519: Failed to get/set credential with map fks and key null in bootstrap credstore. Reason oracle.security.jps.service.keystore.KeyStoreServiceException: JPS-06519: Failed to get/set credential with map fks and key current.key in bootstrap credstore. Reason null
        at oracle.security.jps.internal.keystore.util.KeyStoreServiceUtil.getMasterKey(KeyStoreServiceUtil.java:453)
        at oracle.security.jps.internal.keystore.file.FileKeyStoreManager$3.run(FileKeyStoreManager.java:412)
        at oracle.security.jps.internal.keystore.file.FileKeyStoreManager$3.run(FileKeyStoreManager.java:410)
        at java.security.AccessController.doPrivileged(Native Method)
        at oracle.security.jps.internal.keystore.file.FileKeyStoreManager.openKeyStore(FileKeyStoreManager.java:410)
        Truncated. see log file for complete stacktrace
Caused By: oracle.security.jps.service.keystore.KeyStoreServiceException: JPS-06519: Failed to get/set credential with map fks and key current.key in bootstrap credstore. Reason null
        at oracle.security.jps.internal.keystore.util.KeyStoreServiceUtil.getCurrentMasterKeyAlias(KeyStoreServiceUtil.java:303)
        at oracle.security.jps.internal.keystore.util.KeyStoreServiceUtil$3.run(KeyStoreServiceUtil.java:446)
        at oracle.security.jps.internal.keystore.util.KeyStoreServiceUtil$3.run(KeyStoreServiceUtil.java:444)
        at java.security.AccessController.doPrivileged(Native Method)
        at oracle.security.jps.internal.keystore.util.KeyStoreServiceUtil.getMasterKey(KeyStoreServiceUtil.java:444)
        Truncated. see log file for complete stacktrace
Caused By: oracle.security.jps.service.credstore.CredStoreException: JPS-01061: Access to bootstrap credential store denied to application code.

Solution:


1.Delete all pki files under /tmp and rename keystores.xml(domain/config) and cwallet.sso(domain/config/fmwconfig/bootstrap).
2. Delete the tmp directory under the $DOMAIN_HOME/servers/AdminServer
3.Start the weblogic server


Happy Learning!

Wednesday, 11 July 2018

Oracle EBS R12.2 : Check Ports in Run Edition and Patch Edition



Check Context Files Version are the same in Database


select path,status,serial_number,version
  from apps.fnd_oam_context_files
 where name not in ('TEMPLATE','METADATA') and (status is null or status !='VALID')
order by path, version;


Check Ports in Run Edition

SELECT  extractValue(XMLType(TEXT),'//host[@oa_var="s_hostname"]'),
extractValue(XMLType(TEXT),'//oacore_server_ports'),
extractValue(XMLType(TEXT),'//forms_server_ports'),
extractValue(XMLType(TEXT),'//oafm_server_ports'),
extractValue(XMLType(TEXT),'//forms-c4ws_server_ports'),
extractValue(XMLType(TEXT),'//oaea_server_ports')
from apps.fnd_oam_context_files
where name not in ('TEMPLATE','METADATA')
and (status is null or status !='H')
and EXTRACTVALUE(XMLType(TEXT),'//file_edition_type')='run'
and CTX_TYPE = 'A';


Check Ports in Patch Edition

SELECT  extractValue(XMLType(TEXT),'//host[@oa_var="s_hostname"]'),
extractValue(XMLType(TEXT),'//oacore_server_ports'),
extractValue(XMLType(TEXT),'//forms_server_ports'),
extractValue(XMLType(TEXT),'//oafm_server_ports'),
extractValue(XMLType(TEXT),'//forms-c4ws_server_ports'),
extractValue(XMLType(TEXT),'//oaea_server_ports')
from apps.fnd_oam_context_files
where name not in ('TEMPLATE','METADATA')
and (status is null or status !='H')
and EXTRACTVALUE(XMLType(TEXT),'//file_edition_type')='patch'
and CTX_TYPE = 'A';

Wednesday, 27 December 2017

Trace Forms Enable – Oracle EBS R12


Enable Trace from Forms

Help -> Diagnostic -> Trace ->

we have many options available (default is ‘No Trace’). We can enable tracing by selecting on of the options from here. ‘Regular Trace’ gives the least information and ‘Trace with Binds and Waits’ (level 12) gives maximum information. 

Note: Be careful while enabling SQL trace with wait and binds as this will make the trace file huge.

So after we fill all the values in the fields, we can start the tracing so that the initial select statement does not come in trace file.

When we enable the trace it will give the trace file location (This location will be the location of USER_DUMP_DESTINATION parameter of database).

Disable Trace:
After you save the form you can stop tracing by selecting ‘No Trace’ again from Help -> Diagnostic -> Trace -> No Trace
Use tkprof to covert trace file in readable format.

$ tkprof dv1_ora_35782850.trc dv1_ora_35782850.txt sys=no explain=apps/*******sort='(prsela,exeela,fchela)'


Ref:  Oracle E-Business SQL Trace and TKPROF Guide(1674024.1) 
Metalink note ID 373548.1



Enable Tracing For The Concurrent Manager  Program 
Responsibility: System Administrator
Navigate: Concurrent > Program > Define
Query Concurrent Program
Select the Enable Trace Checkbox 

Turn On Tracing
Responsibility: System Administrator
Navigate: Profiles > System
Query Profile Option Concurrent: Allow Debugging
Set profile to Yes

Run Concurrent Program With Tracing Turned On    
Please login to the Responsibility that runs the Concurrent Program 
In the Submit Request Screen click on Debug Options (B)
Select the Checkbox for SQL Trace

Find Trace File Name

  Run the following SQL to find out the Raw trace name and location for the concurrent program.  The SQL prompts the user for the request id 

SELECT
    req.request_id
    ,req.logfile_node_name node
    ,req.oracle_Process_id
    ,req.enable_trace
    ,dest.VALUE||'/'||LOWER(dbnm.VALUE)||'_ora_'||oracle_process_id||'.trc' trace_filename
    ,prog.user_concurrent_program_name
    ,execname.execution_file_name
    ,execname.subroutine_name
    ,phase_code
    ,status_code
    ,ses.SID
    ,ses.serial#
    ,ses.module
    ,ses.machine
    FROM
    fnd_concurrent_requests req
    ,v$session ses
    ,v$process proc
    ,v$parameter dest
    ,v$parameter dbnm
    ,fnd_concurrent_programs_vl prog
    ,fnd_executables execname
    WHERE 1=1
    AND req.request_id = &request --Request ID

/opt/oracle/enable/admin/ENBL1/udump  --> trace file location



/* Query for Identifying correct trace file for request id */

set lines 800
set pages 400

PROMPT IDENTIFY CONCURRENT REQUEST FILE
PROMPT From Bug.3211206
PROMPT Use the following query to identify the correct trace file:
PROMPT where "request" is the concurrent request id for the inventory transaction 
PROMPT worker. 

SELECT 'Request id: '||request_id ,
'Trace id: '||oracle_Process_id,
'Trace Flag: '||req.enable_trace,
'Trace Name: 
'||dest.value||'/'||lower(dbnm.value)||'_ora_'||oracle_process_id||'.trc',
'Prog. Name: '||prog.user_concurrent_program_name,
'File Name: '||execname.execution_file_name|| execname.subroutine_name ,
'Status : '||decode(phase_code,'R','Running') 
||'-'||decode(status_code,'R','Normal'),
'SID Serial: '||ses.sid||','|| ses.serial#,
'Module : '||ses.module
from apps.fnd_concurrent_requests req, v$session ses, v$process proc,
v$parameter dest, v$parameter dbnm, apps.fnd_concurrent_programs_vl prog, 
apps.fnd_executables execname
where req.request_id = &request
and req.oracle_process_id=proc.spid(+)
and proc.addr = ses.paddr(+)
and dest.name='user_dump_dest'
and dbnm.name='db_name'
and req.concurrent_program_id = prog.concurrent_program_id
and req.program_application_id = prog.application_id
and prog.application_id = execname.application_id
and prog.executable_id=execname.executable_id;




3. TKPROF Trace File

Once you have obtained the Raw trace file you need to generate TKPROF.

output_file: tkprof out file


$ tkprof sys=no explain=apps/ sort=’(prsela,exeela,fchela)’ print=10

Other ways to take trace:
SQL> ALTER SESSION SET sql_trace=TRUE;
SQL> ALTER SESSION SET sql_trace=FALSE;

SQL> EXEC DBMS_SESSION.set_sql_trace(sql_trace => TRUE);
SQL> EXEC DBMS_SESSION.set_sql_trace(sql_trace => FALSE);

SQL> ALTER SESSION SET EVENTS '10046 trace name context forever, level 8';
SQL> ALTER SESSION SET EVENTS '10046 trace name context off';

SQL> EXEC DBMS_SYSTEM.set_sql_trace_in_session(sid=>123, serial#=>1234, sql_trace=>TRUE);
SQL> EXEC DBMS_SYSTEM.set_sql_trace_in_session(sid=>123, serial#=>1234, sql_trace=>FALSE);

SQL> EXEC DBMS_SYSTEM.set_ev(si=>123, se=>1234, ev=>10046, le=>8, nm=>' ');

SQL> EXEC DBMS_SYSTEM.set_ev(si=>123, se=>1234, ev=>10046, le=>0, nm=>' ');

Happy Learning!