Sometimes the User.xml file is corrupted or there is a missing field. You will see the field in the database, in the User Entity object in the System Administration Webapp (with a sandbox open), maybe even in the metadata/iam-features-requestactions/model-data/ModifyUserDataset.xml and CreateUserDataset.xml files. Just missing from the User.xml file.
One way to correct this issue is to hand edit the file. When doing this, use Notepad++ so you can see everything and make sure that the file stays valid (or you can use XMLSpy).
Open the file and search for the UDF section:
find the <entity-attributes> tag. Inside this tag are a collection of <attribute name= tags.
You should (in unix) grep for 'attribute name=' and check to make sure you don't have multiple missing entities, but for this example just concentrate on the one.
Copy any <attribute tag section, all the way to the </attribute> tag, and paste it below. You may have good luck copying something that looks similar to the tag that is missing.
Then do the following:
Change the name in the initial tag name="XXX" to the new field name
Change the name where it is referenced below the <name>scim</name> tag.
Change the value below the <name>max-size</name> tag to the field width. Check the database for this value.
Next go to the <target-fields> tag and find a UDF. Copy and paste a similar <field name= tag, then edit as follows:
Change the name of the initial tag name="xxx" to the new database table field name. It should start with usr_udf.
Next find the <attribute-maps> tag and find an <attribute-map> tag to copy. Copy and then:
Change the name of the entity-attribute to match.
Change the name of the target-field to match.
Next find the <metadata-attachment> tag. Below this are all of your UDFs and several of the OOTB fields. You need to make a spreadsheet of all of the <name> attributes and the the <value> attributes for those entries with category of categories.Basic User Information.
Compile this list and then sort by name. Name is a number. Look for a gap. If there is a gap, I suggest your new entry should fill the gap. If there is no gap, add one to the last value and use it. You will copy a block from the Basic User Information section and rename the value and use the number for name.
Save the file. Import it using the procedure I have outlined in my blog - search on importMetadata
Thanks for viewing my blog on Identity Management and Engineering (mostly IDM). Please follow and check out the advertisers.
Search This Blog
Showing posts with label 11gR2. Show all posts
Showing posts with label 11gR2. Show all posts
Thursday, December 10, 2015
Thursday, October 29, 2015
exportWeblogicMetadata obsolete
In OIM 11gR2 PS3, the weblogic.properties file states that the exportWeblogicMetadata.sh scripts are deprecated. It recommends going to the documentation to find a better way to do this.
The documentation explains that you can use the Enterprise Manager in order to perform targeted exports. I have tried this since 2012 with very little success. I always seem to specify something incorrectly.
Here's another method from the same documentation.
My technique is as follows:
1) Create a new folder for exports. It can be anywhere. For the purposes of this blog, I will use the folder location /u01/app/mds/export
2) cd to the folder $MW_HOME/oracle_common/common/bin Alternatively you could put this in your PATH. Be sure NOT to use the wlst.sh that is in the wlserver folder.
3) execute wlst.sh either through ./wlst.sh or just wlst.sh if it's in your PATH
wlst.sh
connect()
weblogic
<password>
t3://hostname:7001 or t3://admin-vhn:7001 for a clustered install
exportMetadata(application='OIMMetadata',server='oim_server1',toLocation='/u01/app/mds/export')
disconnect()
exit()
It will export all of your data to that folder. You can review all you want.
If you want to import just reverse the process:
mkdir /u01/app/mds/import
Copy only the files that you want to change, keeping their folder structure.
Edit the files (or add files as you please)
wlst.sh
connect()
weblogic
<password>
t3://hostname:7001 or t3://admin-vhn:7001 for a clustered install
importMetadata(application='OIMMetadata',server='oim_server1',fromLocation='/u01/app/mds/import')
disconnect()
exit()
Happy exporting
The documentation explains that you can use the Enterprise Manager in order to perform targeted exports. I have tried this since 2012 with very little success. I always seem to specify something incorrectly.
Here's another method from the same documentation.
My technique is as follows:
1) Create a new folder for exports. It can be anywhere. For the purposes of this blog, I will use the folder location /u01/app/mds/export
2) cd to the folder $MW_HOME/oracle_common/common/bin Alternatively you could put this in your PATH. Be sure NOT to use the wlst.sh that is in the wlserver folder.
3) execute wlst.sh either through ./wlst.sh or just wlst.sh if it's in your PATH
wlst.sh
connect()
weblogic
<password>
t3://hostname:7001 or t3://admin-vhn:7001 for a clustered install
exportMetadata(application='OIMMetadata',server='oim_server1',toLocation='/u01/app/mds/export')
disconnect()
exit()
It will export all of your data to that folder. You can review all you want.
If you want to import just reverse the process:
mkdir /u01/app/mds/import
Copy only the files that you want to change, keeping their folder structure.
Edit the files (or add files as you please)
wlst.sh
connect()
weblogic
<password>
t3://hostname:7001 or t3://admin-vhn:7001 for a clustered install
importMetadata(application='OIMMetadata',server='oim_server1',fromLocation='/u01/app/mds/import')
disconnect()
exit()
Thursday, September 3, 2015
New environment changes to use UploadJars
When you set up a new environment, your UploadJars.sh file won't work until you set up your environment properly. Here is what to do:
Make sure you already have set:
MW_HOME
JAVA_HOME
OIM_ORACLE_HOME
Then set the following environment variables:
APPSERVER_TYPE=wls
APP_SERVER=weblogic
Make sure you already have set:
MW_HOME
JAVA_HOME
OIM_ORACLE_HOME
Then set the following environment variables:
APPSERVER_TYPE=wls
APP_SERVER=weblogic
Tuesday, July 7, 2015
Quick notes on OVD
Some quick notes regarding Oracle Virtual Directory (OVD):
A global plugin is NOT a plugin on the Local Store. Many plugins have a disclaimer that they should not be deployed to an Adapter, such as UPNBind. To define a Global Plugin you need to navigate to the Advanced Tab in ODSM and it is the second section on the left side.
If you are doing a non-join combine of two domains into one, do not use a common top level OU. Define each domain to a unique OU in a common DC and then use the DC as the search base in anything searching for your users.
Monday, July 6, 2015
Sharing log files with users who are not in the oinstall group
Sometimes a client wants to be able for a user to view log files for an Oracle application. There are many ways to do this:
/u01/oracle/products/middleware
and in there you have a domain home of
$MW_HOME/user_projects/domains/oim_domain
and in there you have a server
$DOMAIN_HOME/servers/oim_server1
In this case every folder between /u01 and oim_server1 would have to be granted 755 privileges. It is easy enough to just go through and chmod each folder in order and then check from a user who has not been granted any of 1-3.
Next, the umask in the .bash_profile does have to be 0027 or better for people to read the files if they are in the correct group.
To make this work here is what needs to happen:
As root, execute the command:
# groupadd oshare
(I made up that group name oshare but you can call it whatever you want).
# usermod -a -G oshare oracle
# usermod -a -G oshare username
(username is the user you want to share files with)
# cd <that oim_server1 folder>
# chown -R oracle:oshare logs
# chmod -R 2755 logs
That should do it. I have not tested this.
To reverse this go back and perform:
# chown -R oracle:oinstall logs
If you want the user to be able to delete files and not just read them, change the 2755 above to 2775.
You will have to do this in any log folder you want to share. I would not advise sharing any other folder. This does include the ADR folders.
- Give the user sudo rights to the oracle user.
- Put the user in the oinstall group (assuming that was the default group used in the installation for the oracle user)
- Open up the umask to 0022 so that any user can read the files.
- Do the following:
/u01/oracle/products/middleware
and in there you have a domain home of
$MW_HOME/user_projects/domains/oim_domain
and in there you have a server
$DOMAIN_HOME/servers/oim_server1
In this case every folder between /u01 and oim_server1 would have to be granted 755 privileges. It is easy enough to just go through and chmod each folder in order and then check from a user who has not been granted any of 1-3.
Next, the umask in the .bash_profile does have to be 0027 or better for people to read the files if they are in the correct group.
To make this work here is what needs to happen:
As root, execute the command:
# groupadd oshare
(I made up that group name oshare but you can call it whatever you want).
# usermod -a -G oshare oracle
# usermod -a -G oshare username
(username is the user you want to share files with)
# cd <that oim_server1 folder>
# chown -R oracle:oshare logs
# chmod -R 2755 logs
That should do it. I have not tested this.
To reverse this go back and perform:
# chown -R oracle:oinstall logs
If you want the user to be able to delete files and not just read them, change the 2755 above to 2775.
You will have to do this in any log folder you want to share. I would not advise sharing any other folder. This does include the ADR folders.
Wednesday, June 3, 2015
Fix to issue of not being able to write Lookup group name
There is a new bug 21171801 that I requested to be created. This bug has likely been with OIM for some time and is in all versions I can find.
The bug was first reported in 2013. Here is the issue: when attempting to update the group name of a lookup using the API, the write fails. Very few people read or write lookups using the API. I have written a schedule task to back up and restore lookups.
The bug is in the name of the Field lookup called Lookup Definition.Group which translates to LKU_TYPE_GROUP. If you query the LKU table for the field lookups you will see that each field lookup translates to a table field name in the database. There is no LKU_TYPE_GROUP in the database, it is called LKU_GROUP.
Field lookups cannot be exported, imported, or modified in the Design Console. The only fix to this is the following command executed as the OIM schema owner:
SQL> UPDATE LKU SET LKU_FIELD='LKU_GROUP' WHERE
2 LKU_TYPE_STRING_KEY='Lookup Definition.Group';
SQL> COMMIT;
I constructed this update query this way to prevent someone from accidentally forgetting the second line. This change has no effect on imports, exports, or editing of the Lookups including updating the lookup group name of any lookup. This translation appears to only be used by the API and does not appear to be used by the Design Console or Nexaweb, both of which are supposedly connected via the EJBs directly to the database.
I will update this blog when a patch for this bug is released.
The bug was first reported in 2013. Here is the issue: when attempting to update the group name of a lookup using the API, the write fails. Very few people read or write lookups using the API. I have written a schedule task to back up and restore lookups.
The bug is in the name of the Field lookup called Lookup Definition.Group which translates to LKU_TYPE_GROUP. If you query the LKU table for the field lookups you will see that each field lookup translates to a table field name in the database. There is no LKU_TYPE_GROUP in the database, it is called LKU_GROUP.
Field lookups cannot be exported, imported, or modified in the Design Console. The only fix to this is the following command executed as the OIM schema owner:
SQL> UPDATE LKU SET LKU_FIELD='LKU_GROUP' WHERE
2 LKU_TYPE_STRING_KEY='Lookup Definition.Group';
SQL> COMMIT;
I constructed this update query this way to prevent someone from accidentally forgetting the second line. This change has no effect on imports, exports, or editing of the Lookups including updating the lookup group name of any lookup. This translation appears to only be used by the API and does not appear to be used by the Design Console or Nexaweb, both of which are supposedly connected via the EJBs directly to the database.
I will update this blog when a patch for this bug is released.
Wednesday, May 13, 2015
Adding the valueChangeListener to the modify user sandbox
A modify user sandbox will not have the valueChangeListener set properly for those new fields that were added, and so those need to be added. Here is what to do:
Make a copy of the sandbox.
Using 7-Zip, perform an Extract to: the folder name.
Nav into the folder notice the folders mdssys, oracle, pageDefs, and templates.
Find the file oracle\iam\ui\runtime\form\view\pages\mdssys\cust\site\site\userModifyForm.jsff.xml
Edit this with notepad++
Look for fields that are missing this:
Review each UI component and verify it has a value of
valueChangeListener="#{pageFlowScope.cartDetailStateBean.attributeValueChangedListener}"
You will find that the checkboxes are missing this. It goes after value= tag. Some inputText fields may also be missing this.
look for <af:inputText
look for <af:selectBooleanCheckbox
look for <af:selectOneChoice
look for <af:inputDate also make sure they all have that tag.
When done do the following:
in the folder with the 4 folders mentioned above in it, select them all and do a right click send to compressed archive. The archive will be called templates.zip just rename it and then use that sandbox for the procedure.
Go into the identity page and import the new file. Activate the file and then verify functionality before publishing it. Be sure to sign out and close all windows and tabs of the browser.
Make a copy of the sandbox.
Using 7-Zip, perform an Extract to: the folder name.
Nav into the folder notice the folders mdssys, oracle, pageDefs, and templates.
Find the file oracle\iam\ui\runtime\form\view\pages\mdssys\cust\site\site\userModifyForm.jsff.xml
Edit this with notepad++
Look for fields that are missing this:
Review each UI component and verify it has a value of
valueChangeListener="#{pageFlowScope.cartDetailStateBean.attributeValueChangedListener}"
You will find that the checkboxes are missing this. It goes after value= tag. Some inputText fields may also be missing this.
look for <af:inputText
look for <af:selectBooleanCheckbox
look for <af:selectOneChoice
look for <af:inputDate also make sure they all have that tag.
When done do the following:
in the folder with the 4 folders mentioned above in it, select them all and do a right click send to compressed archive. The archive will be called templates.zip just rename it and then use that sandbox for the procedure.
Go into the identity page and import the new file. Activate the file and then verify functionality before publishing it. Be sure to sign out and close all windows and tabs of the browser.
Tuesday, April 21, 2015
What's in that Sandbox (UDF)
Opening up a sandbox that was exported after creating a UDF, you should find:
mdssys
persdef
xliffBundles
folders.
In the mdssys folder you will find:
sandbox/active_mdsSandboxMetadata.xml which contains the basic info on the sandbox, including the name you gave it when you created it, and the date and time, which you should have put into the name of the sandbox, like this:
Client_yyyyMMdd_HHmm
In the persdef folder you will find:
oracle/iam/ui/common/model/user/entity/mdssys/cust/site/site/UserEO.xml.xml which contains the definition of the UserEO object. Grep on "Attribute Name" to get a list of all of the UserEO elements in the sandbox. Your new ones should be there.
oracle/iam/ui/common/model/user/view/mdssys/cust/site/site/UserVO.xml.xml which contains the definition of the UserVO object. Grep on "ViewAttribute Name" to get a list of all of the UserVO elements in the sandbox. Your new ones should be there.
In the xliffBundles folder you will find oracle/iam/ui/runtime/BizEditorBundle.xlf which contains the ADF mappings for all of the UI components. Grep on user.entity.userEO to see all of the UserEO elements. Your new objects should be there.
mdssys
persdef
xliffBundles
folders.
In the mdssys folder you will find:
sandbox/active_mdsSandboxMetadata.xml which contains the basic info on the sandbox, including the name you gave it when you created it, and the date and time, which you should have put into the name of the sandbox, like this:
Client_yyyyMMdd_HHmm
In the persdef folder you will find:
oracle/iam/ui/common/model/user/entity/mdssys/cust/site/site/UserEO.xml.xml which contains the definition of the UserEO object. Grep on "Attribute Name" to get a list of all of the UserEO elements in the sandbox. Your new ones should be there.
oracle/iam/ui/common/model/user/view/mdssys/cust/site/site/UserVO.xml.xml which contains the definition of the UserVO object. Grep on "ViewAttribute Name" to get a list of all of the UserVO elements in the sandbox. Your new ones should be there.
In the xliffBundles folder you will find oracle/iam/ui/runtime/BizEditorBundle.xlf which contains the ADF mappings for all of the UI components. Grep on user.entity.userEO to see all of the UserEO elements. Your new objects should be there.
Tuesday, April 14, 2015
ICF DBAT Connector Trusted Recon
I originally posted this on the Oracle Community site but I thought I would add it here:
--- START OF POST ---
My colleague and I have written a Database Tables ICF connector and this is an update regarding doing multiple trusted recons.
The data is written to a staging table as events rather than what normally you would think of as a summary table (USR is a good example of a summary table). There are about a dozen events. Only one event is valid to trigger a Create User task, carrying with it about 20 of the user's initial data fields, and such I program the Last Name, OIM Organization Name, OIM User Type, and OIM Employee Type into the attribute map when I pass it to the ResultsHandler.
For an update only recon profiles and update tasks. I originally did not believe that I would need to pass in the Last Name, OIM Organization Name, OIM User Type, and OIM Employee Type parameters into the Resource Object since it only does updates. Since it never creates a user (no match=do nothing), there should be no need for these parameters in the Resource Object. But when I run the Recon I got an error: The profile might be corrupt and could possibly cause reconciliation failure:: xxxxx xxxxxx xxxxxx xxxxxx missing mappings for: [ACT_KEY, USR_LAST_NAME, USR_TYPE, USR_EMP_TYPE] and I get an error XL_SP_ReconBlkUsrRqdcValdnMtch while processing batch ID xxx One or more parameters passed as null
The resolution is this: Any trusted recon must map to these four parameters even if they are not provided in the lookup or the scheduled job. For an update only job you just leave them blank.
--- END OF POST ---
Since I wrote this (in 2013) I did also start putting the 3 normally fixed values of Organization Name, Xellerate Type, and Role, spelled exactly that way, into the RO, the PD, and the Lookup.XX.UM.ReconAttrMap.Trusted.Defaults lookup, instead of trying to generate them inside the connector. This is only needed in the lookup for a recon that can do a create. Otherwise, as stated above, put them into the RO and PD and leave them off of the lookup. Of course Last Name is normally provided in a lookup, but if not then use the same process, put Last Name into the RO and PD and leave unmapped for UPDATES.
The names OIM Organization Name, OIM User Type, and OIM Employee Type are not the correct names, they were just made up.
--- START OF POST ---
My colleague and I have written a Database Tables ICF connector and this is an update regarding doing multiple trusted recons.
The data is written to a staging table as events rather than what normally you would think of as a summary table (USR is a good example of a summary table). There are about a dozen events. Only one event is valid to trigger a Create User task, carrying with it about 20 of the user's initial data fields, and such I program the Last Name, OIM Organization Name, OIM User Type, and OIM Employee Type into the attribute map when I pass it to the ResultsHandler.
For an update only recon profiles and update tasks. I originally did not believe that I would need to pass in the Last Name, OIM Organization Name, OIM User Type, and OIM Employee Type parameters into the Resource Object since it only does updates. Since it never creates a user (no match=do nothing), there should be no need for these parameters in the Resource Object. But when I run the Recon I got an error: The profile might be corrupt and could possibly cause reconciliation failure:: xxxxx xxxxxx xxxxxx xxxxxx missing mappings for: [ACT_KEY, USR_LAST_NAME, USR_TYPE, USR_EMP_TYPE] and I get an error XL_SP_ReconBlkUsrRqdcValdnMtch while processing batch ID xxx One or more parameters passed as null
The resolution is this: Any trusted recon must map to these four parameters even if they are not provided in the lookup or the scheduled job. For an update only job you just leave them blank.
--- END OF POST ---
Since I wrote this (in 2013) I did also start putting the 3 normally fixed values of Organization Name, Xellerate Type, and Role, spelled exactly that way, into the RO, the PD, and the Lookup.XX.UM.ReconAttrMap.Trusted.Defaults lookup, instead of trying to generate them inside the connector. This is only needed in the lookup for a recon that can do a create. Otherwise, as stated above, put them into the RO and PD and leave them off of the lookup. Of course Last Name is normally provided in a lookup, but if not then use the same process, put Last Name into the RO and PD and leave unmapped for UPDATES.
The names OIM Organization Name, OIM User Type, and OIM Employee Type are not the correct names, they were just made up.
Friday, March 13, 2015
Utility classes available for Process Task Adapters
Some people are familiar with a set of classes that are intended for the user to build Process Task Adapters with. These are the thortech classes and they work fine for a lot of generic functionality. Since you can't compile them you may choose to write your own, but they work fine.
You will find them sandwiched between the com.sun and the java.applet classes:
com.thortech.xl.util.adapters.tcUtilBooleanOperations
com.thortech.xl.util.adapters.tcUtilDateOperations
com.thortech.xl.util.adapters.tcUtilHashTableOperations
com.thortech.xl.util.adapters.tcUtilJDBCClass
com.thortech.xl.util.adapters.tcUtilJDBCOperations
com.thortech.xl.util.adapters.tcUtilLDAPController
com.thortech.xl.util.adapters.tcUtilLDAPListener
com.thortech.xl.util.adapters.tcUtilLDAPOrganizationHierarchy
com.thortech.xl.util.adapters.tcUtilMathOperations
com.thortech.xl.util.adapters.tcUtilNumberOperations
com.thortech.xl.util.adapters.tcUtilPSTools
com.thortech.xl.util.adapters.tcUtilStringOperations
com.thortech.xl.util.adapters.tcUtilXellerateOperations
You will find them sandwiched between the com.sun and the java.applet classes:
com.thortech.xl.util.adapters.tcUtilBooleanOperations
com.thortech.xl.util.adapters.tcUtilDateOperations
com.thortech.xl.util.adapters.tcUtilHashTableOperations
com.thortech.xl.util.adapters.tcUtilJDBCClass
com.thortech.xl.util.adapters.tcUtilJDBCOperations
com.thortech.xl.util.adapters.tcUtilLDAPController
com.thortech.xl.util.adapters.tcUtilLDAPListener
com.thortech.xl.util.adapters.tcUtilLDAPOrganizationHierarchy
com.thortech.xl.util.adapters.tcUtilMathOperations
com.thortech.xl.util.adapters.tcUtilNumberOperations
com.thortech.xl.util.adapters.tcUtilPSTools
com.thortech.xl.util.adapters.tcUtilStringOperations
com.thortech.xl.util.adapters.tcUtilXellerateOperations
There's a lot to love so check them out. I use the tcUtilStringOperations the most.
Tuesday, March 3, 2015
Plugins folder and JavaTasks folder - danger
This blog is regarding the plugins and JavaTasks folders in OIM 11gR2++
Most people know that you can easily deploy plugins to the plugins folder found in the $OIM_HOME folder. It is a very simple way to be able to quickly test changes to your event handlers and scheduled tasks.
Some people know about the JavaTasks folder, which does not exist OOTB, but if created in the $OIM_HOME folder, any Jar files contained therein will be taken in just as if they had been uploaded. It still normally requires a restart, but some people don't like the DeleteJars and UploadJars process.
So there is a downside to using these. You cannot export Scheduled Jobs that were built with plugins folder based Scheduled Task plugins. They don't show up in the export list. And even if you register the plugin, when you export, the Job won't import. I suspect similar issues will occur with PTA's built from the JavaTasks folder.
If you have built scheduled jobs from a plugins folder plugin, do this:
1) Screenshot the scheduled job so you remember what you had in it. If any field goes past the end of the editor, just open the screen shot with paint and type in a text box with the data. Save the screenshot.
2) Delete all scheduled jobs that were built from this plugin.
3) Remove the plugin from the plugins folder. I like to just mv them to the plugin_utiliity folder.
4) Watch the oim_serverX-diagnostic.log for the line indicating the plugin has been removed from the cache.
5) Register the plugin
6) Create the scheduled jobs new.
7) Now you can export and import the jobs. Make sure the scheduled task is also registered on the downstream environment.
One more thing:
Never use UpdateJars.sh - even if the file has the same name it sometimes fails to update the jar. Always use DeleteJars.sh, then check the OIMHOME_JARS table, then use UploadJars.sh, and then check the table again.
Peace be with you.
Wednesday, February 18, 2015
OIM 11gR2 Connector Server logging mojo
The OOTB ConnectorServer.exe.Config file contains the following <listeners> tag:
<listeners>
<remove name="Default" />
<add name="myListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="c:\connectorserver.log"
traceOutputOptions="DateTime">
<filter type="System.Diagnostics.EventTypeFilter"
initializeData="Information"/>
</add>
</listeners>
This produces a single file in the c: drive. This file can, and does, grow with no way to roll or otherwise start the file over, except to stop the connector server, delete the file, and then restart the connector server.
Instead of using the TextWriterTraceListener, another option can be chosen.
Here is the other option:
<listeners>
<remove name="Default" />
<add name="FileLog"
type="Microsoft.VisualBasic.Logging.FileLogTraceListener,Microsoft.VisualBasic,Version=8.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a"
initializeData="FileLogWriter"
traceOutputOptions="DateTime"
BaseFileName="ConnectorServer"
Location="Custom"
MaxFileSize="600000000"
CustomLocation="D:\Identity Connectors\Logs\"
LogFileCreationSchedule="Daily">
<filter type="System.Diagnostics.EventTypeFilter" initializeData="Information" />
</add>
</listeners>
You will need to find a way to clean up the log files with an external process. The FileLogTraceListener does not have any options for deleting logs. See these links:
FileLogTraceListener
TraceOutputOptions Values
<listeners>
<remove name="Default" />
<add name="myListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="c:\connectorserver.log"
traceOutputOptions="DateTime">
<filter type="System.Diagnostics.EventTypeFilter"
initializeData="Information"/>
</add>
</listeners>
This produces a single file in the c: drive. This file can, and does, grow with no way to roll or otherwise start the file over, except to stop the connector server, delete the file, and then restart the connector server.
Instead of using the TextWriterTraceListener, another option can be chosen.
Here is the other option:
<listeners>
<remove name="Default" />
<add name="FileLog"
type="Microsoft.VisualBasic.Logging.FileLogTraceListener,Microsoft.VisualBasic,Version=8.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a"
initializeData="FileLogWriter"
traceOutputOptions="DateTime"
BaseFileName="ConnectorServer"
Location="Custom"
MaxFileSize="600000000"
CustomLocation="D:\Identity Connectors\Logs\"
LogFileCreationSchedule="Daily">
<filter type="System.Diagnostics.EventTypeFilter" initializeData="Information" />
</add>
</listeners>
You will need to find a way to clean up the log files with an external process. The FileLogTraceListener does not have any options for deleting logs. See these links:
FileLogTraceListener
TraceOutputOptions Values
Getting java.util.logging to work with JUnit
In my development I normally create the JUnit test cases, but had trouble getting the java.util.logging statement to activate in the code I was testing. I discovered a couple articles on the web and pieced them together for a solution.
As a reference, here is how I normally implement logging, with my OIM Flat File Connector XMLParser as the class:
import java.util.logging.*;
public class FlatFileXMLParser implements FlatFileParser {
private static final Logger logger =
Logger.getLogger(FlatFileXMLParser.class.getName());
public void parse(File flatFile, FlatFileRecordHandler recordHandler,
ParserConfig config) throws Exception {
String methodName="parse";
logger.logp(Level.FINE, getClass().getName(), methodName,
"FF-XMLP-001 entering");
Some explanation:
1) I use java.util.logging and never use log4j.
2) I use logp - never anything else. One statement=commonality
3) I define String methodName to provide the method name in every module.
4) I add tags so that I can grep on the tags. Each statement gets a tag.
5) Increment the numbers in the method and skip to next 100 on next method.
6) Debug statements as Level.FINE, use good judgement.
When I attempt to test these code modules I found that the logging was not being generated. I found a great writeup and took most of this from it. What I did was put the following into the JUnit class - not in the functional class:
public class AppTest extends TestCase {
static {
Logger rootLogger = Logger.getLogger("");
System.setProperty("java.util.logging.SimpleFormatter.format",
"[%1$tF %1$tr] [%2$s] %4$s: %5$s %n");
for(Handler handler : rootLogger.getHandlers()) {
handler.setLevel(Level.FINEST);
handler.setFormatter(new SimpleFormatter());
}
rootLogger.setLevel(Level.FINEST);
}
After this is the constructor and the test methods. The logger will record the details to the output screen and you can track your code.
Good luck testing !!
As a reference, here is how I normally implement logging, with my OIM Flat File Connector XMLParser as the class:
import java.util.logging.*;
public class FlatFileXMLParser implements FlatFileParser {
private static final Logger logger =
Logger.getLogger(FlatFileXMLParser.class.getName());
public void parse(File flatFile, FlatFileRecordHandler recordHandler,
ParserConfig config) throws Exception {
String methodName="parse";
logger.logp(Level.FINE, getClass().getName(), methodName,
"FF-XMLP-001 entering");
Some explanation:
1) I use java.util.logging and never use log4j.
2) I use logp - never anything else. One statement=commonality
3) I define String methodName to provide the method name in every module.
4) I add tags so that I can grep on the tags. Each statement gets a tag.
5) Increment the numbers in the method and skip to next 100 on next method.
6) Debug statements as Level.FINE, use good judgement.
When I attempt to test these code modules I found that the logging was not being generated. I found a great writeup and took most of this from it. What I did was put the following into the JUnit class - not in the functional class:
public class AppTest extends TestCase {
static {
Logger rootLogger = Logger.getLogger("");
System.setProperty("java.util.logging.SimpleFormatter.format",
"[%1$tF %1$tr] [%2$s] %4$s: %5$s %n");
for(Handler handler : rootLogger.getHandlers()) {
handler.setLevel(Level.FINEST);
handler.setFormatter(new SimpleFormatter());
}
rootLogger.setLevel(Level.FINEST);
}
After this is the constructor and the test methods. The logger will record the details to the output screen and you can track your code.
Good luck testing !!
Friday, May 30, 2014
Coding against specific OIM bundle patch jars
One of the difficulties of coding with the OIM API is that it occasionally changes. A specific example occurred sometime before OIM 11gR2 BP11 where the behavior of the ProvisioningService.getAccountsProvisionedToUser(usrKey, searchCriteria) method call changed; at BP11 and above, this method call no longer returns the AccountData object in the Account instance. This can obviously cause problems, and the person coding the Event Handler, Scheduled Task, or Process Task jar file won't know about the change until run time. Use of Maven and JUnit testing will expose these issues during unit testing and prevent problems from occurring.
Best practice for dealing with this is to pull the needed jars file from the OIM server and push them up as jar files in your Maven repository. One example that is used to provide many of the APIs is the file oimclient.jar so that will be described here.
I use a numbering scheme to reference the version similar to what Oracle does, for example the oimclient.jar file from the base R2, BP11 will be 11.1.2.0.11 and the oimclient.jar file from PS2 BP1 would be 11.1.2.2.1 and so on. You can specify the version in your Maven dependencies of the pom file, but that doesn't make the file go into the repo. You have to do that manually.
Here's how to push, for example, the oimclient.jar file from R2 BP11 up to Maven:
mvn install:install-file -Dfile=oimclient.jar -DgroupId=com.oracle -DartifactId=oimclient -Dversion=11.1.2.0.11 -Dpackaging=jar
Once that is pushed you can reference it successfully in your pom file.
One last thing, where do you get the oimclient.jar file from BP11 (or any BP)? You should know by now that for R2, bundle patches are not done by overwriting all of the jars with new jars, and so you can't go into the bundle patch zip file and just pull out the jar files. Bundle patches occasionally have a whole new jar file, usually if a class is to be removed from a jar, but most bundle patches are deltas, where in the patch folder the new classes are organized and the patch process replaces the class files in the jar files in place. So the moral of the story is you have to patch a system before you can pull out the latest jar files, those jar files are nothing more than the current state of an organic system. To figure out where the file is, use find:
$ find $MW_HOME -name oimclient.jar -ls
Best practice for dealing with this is to pull the needed jars file from the OIM server and push them up as jar files in your Maven repository. One example that is used to provide many of the APIs is the file oimclient.jar so that will be described here.
I use a numbering scheme to reference the version similar to what Oracle does, for example the oimclient.jar file from the base R2, BP11 will be 11.1.2.0.11 and the oimclient.jar file from PS2 BP1 would be 11.1.2.2.1 and so on. You can specify the version in your Maven dependencies of the pom file, but that doesn't make the file go into the repo. You have to do that manually.
Here's how to push, for example, the oimclient.jar file from R2 BP11 up to Maven:
mvn install:install-file -Dfile=oimclient.jar -DgroupId=com.oracle -DartifactId=oimclient -Dversion=11.1.2.0.11 -Dpackaging=jar
Once that is pushed you can reference it successfully in your pom file.
One last thing, where do you get the oimclient.jar file from BP11 (or any BP)? You should know by now that for R2, bundle patches are not done by overwriting all of the jars with new jars, and so you can't go into the bundle patch zip file and just pull out the jar files. Bundle patches occasionally have a whole new jar file, usually if a class is to be removed from a jar, but most bundle patches are deltas, where in the patch folder the new classes are organized and the patch process replaces the class files in the jar files in place. So the moral of the story is you have to patch a system before you can pull out the latest jar files, those jar files are nothing more than the current state of an organic system. To figure out where the file is, use find:
$ find $MW_HOME -name oimclient.jar -ls
Wednesday, May 21, 2014
Location of some jar files in OIM
Sometimes it is difficult to remember where the jar files are in OIM. Here's my running list.
oracle.iam.connectors.icfcommon.* are in icf-oim-intg.jar
most of the rest of oracle.iam are located in OIMServer.jar including:
The implementation for ProvisioningService is in OIMServer.jar under:
oracle.iam.provisioning.implProvisioningServiceImpl
oracle.iam.selfservice.self.selfmgmt.impl.AuthenticatedSelfServiceImpl
oracle.iam.identity.usermgmt.impl.UserManagerImpl
oracle.iam.platform.tx.OIMTransactionManager is in oimclient.jar, iam-platform-utils.jar
com.thortech.xl.xjb.beansimpl.tcLookupOperationsBean is in xlDataObjectBeans.jar
org.apache.xml.serializer.ToStream is in xalan-2.6.0.jar
Thor.API.Operations.* interfaces, are implemented by classes in com.thortech.xl.ejb.beansimpl and are in the xlDataObjectBeans.jar file.
These often call a class com.thortech.xl.dataobj.APIUtils which is found in xlDataObjects.jar
Mappings getMapping are done by com.thortech.xl.orb.api.tcMapping which is in xlVO.jar which just converts a Map into an array of tcMapping objects.
The conversions are done in getColumnNameMap which maps the long values into short ones. This is done in Thor.API.tcBaseUtility.getColumnNameMap and is in oimclient.jar
The query is:
select lku_field, lku_type_string_key from lku where lku_type='f' and lku_type_string_key in (" + msbCodeList + ")";
I have a utility called findclass that I use to search jar files for class names.
Design Console - designconsole - The name of the Design Console is tcAppWindow and it is located in the file $OIM_ORACLE_HOME/server/client/lib/XellerateClient.jar
oracle.iam.connectors.icfcommon.* are in icf-oim-intg.jar
most of the rest of oracle.iam are located in OIMServer.jar including:
The implementation for ProvisioningService is in OIMServer.jar under:
oracle.iam.provisioning.implProvisioningServiceImpl
oracle.iam.selfservice.self.selfmgmt.impl.AuthenticatedSelfServiceImpl
oracle.iam.identity.usermgmt.impl.UserManagerImpl
oracle.iam.platform.tx.OIMTransactionManager is in oimclient.jar, iam-platform-utils.jar
com.thortech.xl.xjb.beansimpl.tcLookupOperationsBean is in xlDataObjectBeans.jar
org.apache.xml.serializer.ToStream is in xalan-2.6.0.jar
Thor.API.Operations.* interfaces, are implemented by classes in com.thortech.xl.ejb.beansimpl and are in the xlDataObjectBeans.jar file.
These often call a class com.thortech.xl.dataobj.APIUtils which is found in xlDataObjects.jar
Mappings getMapping are done by com.thortech.xl.orb.api.tcMapping which is in xlVO.jar which just converts a Map into an array of tcMapping objects.
The conversions are done in getColumnNameMap which maps the long values into short ones. This is done in Thor.API.tcBaseUtility.getColumnNameMap and is in oimclient.jar
The query is:
select lku_field, lku_type_string_key from lku where lku_type='f' and lku_type_string_key in (" + msbCodeList + ")";
I have a utility called findclass that I use to search jar files for class names.
Design Console - designconsole - The name of the Design Console is tcAppWindow and it is located in the file $OIM_ORACLE_HOME/server/client/lib/XellerateClient.jar
Thursday, February 27, 2014
OIM 11gR2 Connector Server setup mojo
Just some simple tips for setting up the connector server. Some of these tips are from my colleagues, some I have modified what my colleagues are doing and so are my own take on things.
When building a connector server machine, it works very well to create a separate disk where all of the connector server software can be loaded and run from. For a physical machine (iron) the D drive will be taken by a CD/DVD drive, and you can use E: for the connector server. On a VM, you could choose to use D: or E:, whatever your preference.
On install never accept the Program Files folder for where the software is installed to. If you followed the advice above you will install the software into the D: or E: drive, if not, install in the C: drive, so your top folder is E:\Identity Connectors (or your drive). Under that you should have a Connector Server folder.
After install, decide where you want to put the log files. The default is C: and that is a bad location for the files. You can put the logs inside the Connector Server folder, in a separate folder, or on a third drive letter, for that matter. I call my logs folder Logs with a capital L since this is Microsoft and we give civilized names to our folders in Windows, not like those "lower case-no blanks" Linux savages.
The bundles of course go into the Connector Server folder per the install guides for each connector. Be sure to set the key first. I will cover logging in a separate post.
I install WinSCP and Notepad++ on my connector servers so I can manage things easily. I also make sure the Remote Admin tools including Active Directory Administrative Center, AD module for Windows PowerShell, Web Server (IIS) Tools, Telnet Client, and .NET 3.5.1 Framework Windows features are installed.
Finally, many people don't know how to set up a VIP on a windows box. The command is:
netsh interface ip add address "Local Area Connection" <vip-address> <netmask>
The name "Local Area Connection" is an example, this needs to be the name of your existing Ethernet adapter. Sometimes it is named Local Area Connection, other times it is named Online Network, but you need to find out what it is called by running ipconfig /all and noting it. You are adding an address to the existing interface, so it needs to be the same.
When building a connector server machine, it works very well to create a separate disk where all of the connector server software can be loaded and run from. For a physical machine (iron) the D drive will be taken by a CD/DVD drive, and you can use E: for the connector server. On a VM, you could choose to use D: or E:, whatever your preference.
On install never accept the Program Files folder for where the software is installed to. If you followed the advice above you will install the software into the D: or E: drive, if not, install in the C: drive, so your top folder is E:\Identity Connectors (or your drive). Under that you should have a Connector Server folder.
After install, decide where you want to put the log files. The default is C: and that is a bad location for the files. You can put the logs inside the Connector Server folder, in a separate folder, or on a third drive letter, for that matter. I call my logs folder Logs with a capital L since this is Microsoft and we give civilized names to our folders in Windows, not like those "lower case-no blanks" Linux savages.
The bundles of course go into the Connector Server folder per the install guides for each connector. Be sure to set the key first. I will cover logging in a separate post.
I install WinSCP and Notepad++ on my connector servers so I can manage things easily. I also make sure the Remote Admin tools including Active Directory Administrative Center, AD module for Windows PowerShell, Web Server (IIS) Tools, Telnet Client, and .NET 3.5.1 Framework Windows features are installed.
Finally, many people don't know how to set up a VIP on a windows box. The command is:
netsh interface ip add address "Local Area Connection" <vip-address> <netmask>
The name "Local Area Connection" is an example, this needs to be the name of your existing Ethernet adapter. Sometimes it is named Local Area Connection, other times it is named Online Network, but you need to find out what it is called by running ipconfig /all and noting it. You are adding an address to the existing interface, so it needs to be the same.
Wednesday, February 26, 2014
Oracle Diagnostic Logging - getting deeper into OIM11gR2
Going deeper into OIM is a little different using ODL instead of the old log4j.properties file in OIM 9.1.0.2
If you have read my previous post on how to set up and hand modify the ODL files for your server, you will be able to perform these tasks.
Here are some interesting logging points I have tried:
<logger name='oracle.iam.provisioning' level='TRACE:32'>
<handler name='odl-handler'/>
</logger>
<logger name='oracle.iam.identity' level='TRACE:1'>
<handler name='odl-handler'/>
</logger>
<logger name='Thor.API.Operations' level='TRACE:32'>
<handler name='odl-handler'/>
</logger>
<logger name='XELLERATE.DATABASE' level='NOTIFICATION:32'>
<handler name='odl-handler'/>
</logger>
<logger name='XELLERATE.SERVER' level='NOTIFICATION:1'>
<handler name='odl-handler'/>
</logger>
<logger name='XELLERATE.SCHEDULER' level='NOTIFICATION:1'>
<handler name='odl-handler'/>
</logger>
The handler name was changed back to odl-handler, but I use my own handler that segregates the parts I am interested in. I put all of the parts I am interested in, into a handler I call edu-handler, so in my logging.xml file, all of the above odl-handler references actually are edu-handler. I just want someone who wants to copy/paste to not have a failure because they haven't defined an edu-handler.
If you have read my previous post on how to set up and hand modify the ODL files for your server, you will be able to perform these tasks.
Here are some interesting logging points I have tried:
<logger name='oracle.iam.provisioning' level='TRACE:32'>
<handler name='odl-handler'/>
</logger>
<logger name='oracle.iam.identity' level='TRACE:1'>
<handler name='odl-handler'/>
</logger>
<logger name='Thor.API.Operations' level='TRACE:32'>
<handler name='odl-handler'/>
</logger>
<logger name='XELLERATE.DATABASE' level='NOTIFICATION:32'>
<handler name='odl-handler'/>
</logger>
<logger name='XELLERATE.SERVER' level='NOTIFICATION:1'>
<handler name='odl-handler'/>
</logger>
<logger name='XELLERATE.SCHEDULER' level='NOTIFICATION:1'>
<handler name='odl-handler'/>
</logger>
The handler name was changed back to odl-handler, but I use my own handler that segregates the parts I am interested in. I put all of the parts I am interested in, into a handler I call edu-handler, so in my logging.xml file, all of the above odl-handler references actually are edu-handler. I just want someone who wants to copy/paste to not have a failure because they haven't defined an edu-handler.
OIM 11gR2 How to make plugins easier to manage
Making plugins easier to manage is simple. I have a prior post that is not as detailed but is still applicable. First, occasionally run this query against your database and export the results:
SELECT DISTINCT(ID) FROM PLUGINS ORDER BY ID ASC
This will give you a list of the current plugins you have. If you want to know more try this query:
SELECT ID,VERSION,NAME,TYPE FROM PLUGINS ORDER BY ID ASC, VERSION DESC
The second query will show if you have multiple versions. The system should pick the highest numbered version, but I do not trust that. IMHO, always keep just the latest copy of each plugin.
The second thing to do is to make the plugin utility easier to use. Here's how: Open the ant.properties file and make sure you have filled in the provided values. I use MW_HOME in these examples but they need to be your $MW_HOME, spelled out in the file.
wls.home=$MW_HOME/wlserver_10.3
oim.home=$MW_HOME/Oracle_IDM1/server
login.config=${oim.home}/config/authwl.conf
mw.home=$MW_HOME
Correction: ant does not pick up the environment variables
mw.home=/u01/app/oracle/fmw
wls.home=/u01/app/oracle/fmw/wlserver_10.3
oim.home=/u01/app/oracle/fmw/Oracle_IDM1/server
Third, add the next 3 lines to the same file:
OIM.Username=xelsysadm
OIM.UserPassword=<your password>
ServerURL=t3://yourservice.yoursystem.yourdomain:14000
CtxFactory=weblogic.jndi.WLInitialContextFactory
Then you just run ant -f pluginregistration.xml unregister
All you have to type in is the password for xelsysadm
and paste the full class name from the export you did in step 1.
For the file names when you are running ant -f pluginregistration.xml register
I copy the files into a /home/oracle/plugins folder and then use:
find ~/plugins -name '*plugin*' -print
And then copy the line with the full pathname before I run the ant script. Again I just enter the password for xelsysadm and then paste the filename.
Be sure to fully stop and restart all servers (no rolling restarts) to make the new plugins active. I have found that PurgeCache does not work.
SELECT DISTINCT(ID) FROM PLUGINS ORDER BY ID ASC
This will give you a list of the current plugins you have. If you want to know more try this query:
SELECT ID,VERSION,NAME,TYPE FROM PLUGINS ORDER BY ID ASC, VERSION DESC
The second query will show if you have multiple versions. The system should pick the highest numbered version, but I do not trust that. IMHO, always keep just the latest copy of each plugin.
The second thing to do is to make the plugin utility easier to use. Here's how: Open the ant.properties file and make sure you have filled in the provided values. I use MW_HOME in these examples but they need to be your $MW_HOME, spelled out in the file.
login.config=${oim.home}/config/authwl.conf
Correction: ant does not pick up the environment variables
mw.home=/u01/app/oracle/fmw
wls.home=/u01/app/oracle/fmw/wlserver_10.3
oim.home=/u01/app/oracle/fmw/Oracle_IDM1/server
Third, add the next 3 lines to the same file:
OIM.Username=xelsysadm
OIM.UserPassword=<your password>
ServerURL=t3://yourservice.yoursystem.yourdomain:14000
CtxFactory=weblogic.jndi.WLInitialContextFactory
Then you just run ant -f pluginregistration.xml unregister
All you have to type in is the password for xelsysadm
and paste the full class name from the export you did in step 1.
For the file names when you are running ant -f pluginregistration.xml register
I copy the files into a /home/oracle/plugins folder and then use:
find ~/plugins -name '*plugin*' -print
And then copy the line with the full pathname before I run the ant script. Again I just enter the password for xelsysadm and then paste the filename.
Be sure to fully stop and restart all servers (no rolling restarts) to make the new plugins active. I have found that PurgeCache does not work.
Thursday, February 20, 2014
OIM 11gR2 - When to use Platform.getServiceForEventHandlers
Just a quick reminder when creating Event Handlers (not for Scheduled Tasks)
UserManager usrMgr=Platform.getService (UserManager.class);
is used when you need to query for user parameters, such as when an orchestration might change one field, and you need to fill in other fields from the USR table in order to provide some kind of an update. An example is Display Name, which, if only the Last Name is changed, you will want to retrieve the First and Middle Name fields in order to properly construct the Display Name.
Platform.getServiceForEventHandlers is used when you want to perform any kind of updates within an Event Handler. Example:
ProvisioningService provSvcUP = Platform.getServiceForEventHandlers(ProvisioningService.class,
null, "ADMIN","XXXHandler", null);
UserManager usrMgr=Platform.getService (UserManager.class);
is used when you need to query for user parameters, such as when an orchestration might change one field, and you need to fill in other fields from the USR table in order to provide some kind of an update. An example is Display Name, which, if only the Last Name is changed, you will want to retrieve the First and Middle Name fields in order to properly construct the Display Name.
Platform.getServiceForEventHandlers is used when you want to perform any kind of updates within an Event Handler. Example:
ProvisioningService provSvcUP = Platform.getServiceForEventHandlers(ProvisioningService.class,
null, "ADMIN","XXXHandler", null);
Tuesday, February 18, 2014
OIM11gR2 Using the old Thor interfaces
Sometimes you need to use the old Thor interfaces for getting information from the system. Lookups are one of these items, and that will be the example used here.
Also see my other posting OIM How to pull an IT Resource Parameter
Import the resource:
import Thor.API.Operations.tcLookupOperationsIntf;
Define the interface (spell something differently, in this case I used lower case L in lookup):
tcLookupOperationsIntf tclookupOperationsIntf =null;
Get the service:
tclookupOperationsintf = Platform.getService(tcLookupOperationsIntf.class);
Optionally you can do this all in one line. You should null check the returned value.
Here's a completed task that just checks to see if a value is in a list:
Thor.API.tcResultSet rs=null;
try {
rs=tclookupOperationsIntf.getLookupValues(validAccountLookup);
int rowcount=rs.getRowCount();
for (int irow=0; irow < rowcount; ++irow) {
rs.goToRow(irow);
String codeKey=rs.getStringValue
("Lookup Definition.Lookup Code Information.Code Key");
String decode=rs.getStringValue
("Lookup Definition.Lookup Code Information.Decode");
if (appInstanceName.equals(codeKey)) {
logger.logp(Level.FINE, getClass().getName(), methodName,
"Found "+appInstanceName+" in row "+irow+", returning true");
return true;
}
}
}
I left out all of the checks and catches, just showing functional code.
Also see my other posting OIM How to pull an IT Resource Parameter
Import the resource:
import Thor.API.Operations.tcLookupOperationsIntf;
Define the interface (spell something differently, in this case I used lower case L in lookup):
tcLookupOperationsIntf tclookupOperationsIntf =null;
Get the service:
tclookupOperationsintf = Platform.getService(tcLookupOperationsIntf.class);
Optionally you can do this all in one line. You should null check the returned value.
Here's a completed task that just checks to see if a value is in a list:
Thor.API.tcResultSet rs=null;
try {
rs=tclookupOperationsIntf.getLookupValues(validAccountLookup);
int rowcount=rs.getRowCount();
for (int irow=0; irow < rowcount; ++irow) {
rs.goToRow(irow);
String codeKey=rs.getStringValue
("Lookup Definition.Lookup Code Information.Code Key");
String decode=rs.getStringValue
("Lookup Definition.Lookup Code Information.Decode");
if (appInstanceName.equals(codeKey)) {
logger.logp(Level.FINE, getClass().getName(), methodName,
"Found "+appInstanceName+" in row "+irow+", returning true");
return true;
}
}
}
I left out all of the checks and catches, just showing functional code.
Subscribe to:
Posts (Atom)