Thursday, March 14, 2013

Fix for Issue with sending Email Notifications in OIM

When we set up a IT Resource in OIM that will be used by either SMTP provider or the UMS to send out emails, there is an issue with emails not going through when an user other than xelsysadm (SYSTEM ADMINISTRATORS role) tries to send emails.

The exception in the logs will be similar to the one below:


[NOTIFICATION] [] [oracle.iam.notification.provider] [tid: [ACTIVE].ExecuteThread: '7' for queue: 'weblogic.kernel.Default (self-tuning)'] [userId: user123] [ecid: 894fa193dcd2578d:50eb0ada:13d63a1396f:-8000-0000000000004597,0] [APP: oim#11.1.2.0.0] IT Resource Email Server is not present.
[ERROR] [] [oracle.iam.notification.impl] [tid: [ACTIVE].ExecuteThread: '7' for queue: 'weblogic.kernel.Default (self-tuning)'] [userId: user123] [ecid: 894fa193dcd2578d:50eb0ada:13d63a1396f:-8000-0000000000004597,0] [APP: oim#11.1.2.0.0] Provider EmailServiceProvider has encountered exception : Authentication failed; nested exception is javax.mail.AuthenticationFailedException
ERROR] [] [oracle.iam.notification.impl] [tid: [ACTIVE].ExecuteThread: '7' for queue: 'weblogic.kernel.Default (self-tuning)'] [userId: user123] [ecid: 894fa193dcd2578d:50eb0ada:13d63a1396f:-8000-0000000000004597,0] [APP: oim#11.1.2.0.0] Sending notification with Provider EmailServiceProvider has encountered exception : Error occured while Sending Notification through Provider EmailServiceProvider : Authentication failed; nested exception is javax.mail.AuthenticationFailedException
ERROR] [] [oracle.iam.notification.impl] [tid: [ACTIVE].ExecuteThread: '7' for queue: 'weblogic.kernel.Default (self-tuning)'] [userId: user123] [ecid: 894fa193dcd2578d:50eb0ada:13d63a1396f:-8000-0000000000004597,0] [APP: oim#11.1.2.0.0] Sending notification with Provider EmailServiceProvider detailed exception : Authentication failed; nested exception is javax.mail.AuthenticationFailedException

The fix for this issue is to add the roles that will use this resource to send out emails to the IT Resource as Administrative Roles. For example if all the users in helpdesklevel1 and helpdesklevel2 roles should also send emails.
Edit the IT resource and then add these roles under Administrative Roles of the It Resource.

Note: Giving Read Access is enough.



Now when any user under these roles try to send an notification from OIM. It would not fail.

Tuesday, March 5, 2013

Custom Common Name Generation Policy Plugin in OIM 11g r2

By default the Common Name Generation Policy used in OIM is "oracle.iam.ldapsync.impl.plugins.FirstNameLastNamePolicy". If you want to use your own policy for example mapping the User ID as Common Name. Here is how it can be achieved.

Create a custom plugin class implementing the CommonNamePolicy:

CustomCommonNamePolicy Class:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.util.Locale;
import java.util.Map;

import static oracle.iam.identity.usermgmt.api.UserManagerConstants.AttributeName.USER_LOGIN;
import oracle.iam.ldapsync.api.CommonNamePolicy;
import oracle.iam.ldapsync.exception.CommonNameGenerationException;


public class CustomCommonNamePolicy implements CommonNamePolicy{
    public CustomCommonNamePolicy() {
        super();
    }

    @Override
    public String getCommonNameFromPolicy(Map<String, Object> userData)throws CommonNameGenerationException {
        return (String) userData.get(USER_LOGIN.getId());
    }

    @Override
    public boolean isCommonNameValid(String commonName, Map<String,Object> userData) {
       return true;
    }

    @Override
    public String getDescription(Locale locale) {
        return "Custom policy - returns user login as common name";
    }
}

Create a plugin xml file with the following content:

plugin.xml file:

1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8"?>
<oimplugins>
    <plugins pluginpoint="oracle.iam.ldapsync.api.CommonNamePolicy">
        <plugin pluginclass="com.plugins.custom.commonname.CustomCommonNamePolicy" version="1.0" name="CustomCommonNamePolicy"/>
    </plugins>
</oimplugins>

Create a zip file CustomCommonNamePolicyPlugin.zip with the following folder structure:
  • The plugin.xml file: the plugin file created above.
  • The lib/ directory: The lib/ directory consists of class files with full package structure that contains the classes implementing the plug-in logic.
  • The resources/ directory: empty folder.
Copy Common Name Generation Policy plugin to the plugins directory:

1. Transfer the Common Name Generation plugin zip file (CustomCommonNamePolicyPlugin.zip) to the $OIM_ORACLE_HOME/server/plugins directory on the server using WinScp or any other sftp software;

Update the OIM system property to use the custom common name generation policy:

1) Login to OIM System Administration Console using the following URL. http://<OIM Server Hostname>:<OIM server Port>/sysadmin and the following connections page will appear as shown in the below:
Note 1: The OIM Server Hostname and OIM server Port values have to be replaced with actual values depending on the environment you are carrying out these steps.
Note 2: A sample URL for accessing OIM System Administration screen is: http://<oim-host>:<oim-port>/sysadmin.

Figure 1: OIM Login page

2) Enter the value for User ID and Password and Click on Sign In as shown in Figure 1 above.
 
Figure 2: OIM page after Login

3) Click on System Configuration under System Management as shown in Figure 2 above.

 Figure 3: Search System Configuration Page

4) Enter *Common* in the search criteria and click search button as highlighted in Figure 3.

 Figure 4: Search Results

5) Click on the CommonName Generation plugin as highlighted in Figure 4.
Figure 5: Search Results

6) Modify the value to have com.custom.commonname.CustomCommonNamePolicy as highlighted in the figure and click Save.

Friday, March 1, 2013

Custom ADF Web application to search users in OIM 11g r2


      1.      Create a new JDeveloper Application. Select Fusion Web Application (ADF) and also make sure you have the Application Package Prefix as oracle.iam.ui.custom and click Next as shown below.




      2.      Modify the model Project name and Click Next.



      3.      Leave Model Project Settings as is and click Next. 


      4.      Modify the View Project Name and Click Next. 




      5.      Leave View Project Settings as is and click Finish. 

      6.      Select the model project and add the following Jar files in the class path. 
       Note: Get the below jars from OIM server OIM_HOME/server/client/lib folder. 




      7.      Create a new Service class in Model Project. Right Click on Model Project and Select New. 




      8.      Select Java Class from General Category and click OK. 




      9.      Give the class name as UIMServiceImpl and Package as oracle.iam.ui.custom.model.service.impl and click OK. 




      10.      Modify the class to have an API to search for User based on the given search Criteria  as shown in the below class definition. 
      Note: Make sure you replace the authwl.conf file location to the correct one before deploying.
      Service class:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package oracle.iam.ui.custom.model.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;

import javax.security.auth.login.LoginException;

import oracle.iam.identity.exception.UserSearchException;
import oracle.iam.identity.usermgmt.api.UserManager;
import oracle.iam.identity.usermgmt.vo.User;
import oracle.iam.platform.OIMClient;
import oracle.iam.platform.entitymgr.vo.SearchCriteria;
import oracle.iam.ui.custom.model.service.bean.UIMUserHelperBean;


public class UIMServiceImpl {
    public UIMServiceImpl() {
        super();
    }
    
    
    protected static final String JAVA_SECURITY_AUTH_LOGIN_CONFIG_KEY = "java.security.auth.login.config";
    protected static final String FIRST_NAME = "First Name";
    protected static final String LAST_NAME = "Last Name";
    protected static final String USER_LOGIN = "User Login";
    protected static final String EMAIL = "Email"; 
    protected static final String STARTROW = "STARTROW";
    protected static final String ENDROW = "ENDROW";
    
    public OIMClient init(){
        OIMClient oimClient = null;
        Hashtable env = new Hashtable();
        env.put(OIMClient.JAVA_NAMING_PROVIDER_URL, "t3://oimhost:oimport");
        env.put(OIMClient.JAVA_NAMING_FACTORY_INITIAL,OIMClient.WLS_CONTEXT_FACTORY);
        System.setProperty("OIM.AppServerType", "wls");
        System.setProperty("APPSERVER_TYPE", "wls");
        System.setProperty(JAVA_SECURITY_AUTH_LOGIN_CONFIG_KEY, "C:\\temp\\config\\authwl.conf");
        oimClient = new OIMClient(env);
        return oimClient;
    }
    
    /**
     * @param firstName
     * @param lastName
     * @return
     */
    public List<UIMUserHelperBean> searchUsersInOIM(String firstName, String lastName){
        
        List<UIMUserHelperBean> usersList = new ArrayList<UIMUserHelperBean>();
        HashMap<String, Object> configParam = new HashMap<String, Object>();
        
        OIMClient oimClient = init();

        //TODO REMOVE THIS SECTION ON ACTUAL IMPL

        try {
            oimClient.login("xelsysadm", "Password123".toCharArray());
            System.out.println("Login Successful");
        } catch (LoginException e) {
            e.printStackTrace();
        }
        configParam.put(STARTROW, 0);
        configParam.put(ENDROW, 1000);
        String userLogin = null;
        List<User> users =null;
        
        System.out.println("Search Criteria: First Name entered is: " + firstName);
        System.out.println("Search Criteria: Last Name entered is: " + lastName);
        
        
        SearchCriteria searchCriteria = new SearchCriteria(FIRST_NAME, firstName+"*", SearchCriteria.Operator.EQUAL);
        SearchCriteria searchCriteria1 = new SearchCriteria(LAST_NAME, lastName+"*", SearchCriteria.Operator.EQUAL); 
        SearchCriteria searchCriteria2 = new SearchCriteria(searchCriteria,searchCriteria1, SearchCriteria.Operator.AND); 
        
        UserManager userManager = oimClient.getService(UserManager.class);

        try {
            users = userManager.search(searchCriteria2, null, configParam);
            System.out.println("Search Results: Size is: " + users.size());
        } catch (UserSearchException e) {
            e.printStackTrace();
        }
        if (users != null && users.size() > 0 ){
            for(User user : users){
                UIMUserHelperBean userFromOIM = new UIMUserHelperBean();
                userFromOIM.setFirstName((String)user.getAttribute(FIRST_NAME));
                userFromOIM.setLastName((String)user.getAttribute(LAST_NAME));
                userFromOIM.setUserId((String)user.getAttribute(USER_LOGIN));
                userFromOIM.setEMail((String)user.getAttribute(EMAIL));
                usersList.add(userFromOIM);
            }
        }
        System.out.println("Return Results: Size is: " + usersList.size());
        return usersList;
    }
}
 

Helper Bean class:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package oracle.iam.ui.custom.model.service.bean;

import java.io.Serializable;

public class UIMUserHelperBean implements Serializable{
    public UIMUserHelperBean() {
        super();
    }
    @SuppressWarnings("compatibility:-3606839465385197186")
    private static final long serialVersionUID = 1L;
    
    public UIMUserHelperBean(String firstName, String lastName, String userId, String eMail) { 
        this.firstName = firstName;
        this.lastName = lastName;
        this.userId = userId;
        this.eMail = eMail;
    }
    
    private String firstName;
    private String lastName;
    private String userId;
    private String eMail;


    public static long getSerialVersionUID() {
        return serialVersionUID;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getUserId() {
        return userId;
    }

    public void setEMail(String eMail) {
        this.eMail = eMail;
    }

    public String getEMail() {
        return eMail;
    }
}


        11.      Add a new Managed Bean by right Clicking on the view project and select General -> Java Class. 

Managed Bean:
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package oracle.iam.ui.custom.app.view.backing.bean;

import java.io.Serializable;

import java.util.ArrayList;

import oracle.adf.view.rich.component.rich.RichDocument;
import oracle.adf.view.rich.component.rich.RichForm;
import oracle.adf.view.rich.component.rich.data.RichTable;
import oracle.adf.view.rich.component.rich.input.RichInputText;
import oracle.adf.view.rich.component.rich.layout.RichPanelBox;
import oracle.adf.view.rich.component.rich.nav.RichCommandButton;
import oracle.adf.view.rich.component.rich.output.RichPanelCollection;
import oracle.adf.view.rich.component.rich.output.RichSeparator;

import oracle.iam.ui.custom.model.service.bean.UIMUserHelperBean;
import oracle.iam.ui.custom.model.service.impl.UIMServiceImpl;


public class SearchUsersBackingBean implements Serializable{
    
    @SuppressWarnings("compatibility:-8242036795925574214")
    private static final long serialVersionUID = 1L;

    private RichForm f1;
    private RichDocument d1;
    private RichPanelBox pb1;
    private RichInputText it1;
    private RichInputText it2;
    private RichCommandButton cb1;
    private ArrayList<UIMUserHelperBean> usersList = null;
    private boolean showResults = false;
    private RichSeparator s1;
    private RichPanelCollection pc1;
    private RichTable t1;


    public void setF1(RichForm f1) {
        this.f1 = f1;
    }

    public RichForm getF1() {
        return f1;
    }

    public void setD1(RichDocument d1) {
        this.d1 = d1;
    }

    public RichDocument getD1() {
        return d1;
    }

    public void setPb1(RichPanelBox pb1) {
        this.pb1 = pb1;
    }

    public RichPanelBox getPb1() {
        return pb1;
    }

    public void setIt1(RichInputText it1) {
        this.it1 = it1;
    }

    public RichInputText getIt1() {
        return it1;
    }

    public void setIt2(RichInputText it2) {
        this.it2 = it2;
    }

    public RichInputText getIt2() {
        return it2;
    }

    public void setCb1(RichCommandButton cb1) {
        this.cb1 = cb1;
    }

    public RichCommandButton getCb1() {
        return cb1;
    }

    public String searchUsersInOIM() {
        UIMServiceImpl oimService = new UIMServiceImpl();
        usersList = (ArrayList<UIMUserHelperBean>)oimService.searchUsersInOIM((String)getIt1().getValue(),(String)getIt2().getValue());
        System.out.println("FirstName from UI: " + getIt1().getValue());
        System.out.println("LastName from UI: " + getIt2().getValue());
        //setDummyResults();
        if(usersList.size() > 0){
            showResults = true;
        }
        return "success";
    }

    public void setUsersList(ArrayList usersList) {
        this.usersList = usersList;
    }

    public ArrayList getUsersList() {
        return usersList;
    }

    public void setS1(RichSeparator s1) {
        this.s1 = s1;
    }

    public RichSeparator getS1() {
        return s1;
    }

    public void setPc1(RichPanelCollection pc1) {
        this.pc1 = pc1;
    }

    public RichPanelCollection getPc1() {
        return pc1;
    }

    public void setT1(RichTable t1) {
        this.t1 = t1;
    }

    public RichTable getT1() {
        return t1;
    }

    public void setShowResults(boolean showResults) {
        this.showResults = showResults;
    }

    public boolean isShowResults() {
        return showResults;
    }
    
}


          12.      Modify the adfc-config.xml file to add the new Managed Bean Information here.


          13.   The source view of the adfc-config.xml looks  like this.


          14.      Add a searchUsers.jspx page in View Project by right clicking on the View Project and clicking New. Select JSF page under Web Tier -> JSF and click OK. 




          15.      Modify the file name and make sure you have Create as XML Document value checked and then click OK. 


           searchUsers.jspx:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
  <jsp:directive.page contentType="text/html;charset=UTF-8"/>
  <f:view>
    <af:document id="d1"
                 binding="#{viewScope.SearchUsersBackingBean.d1}" title="Search Users">
      <af:form id="f1" binding="#{viewScope.SearchUsersBackingBean.f1}">
        <af:panelBox text="Search Users in OIM"
                     binding="#{viewScope.SearchUsersBackingBean.pb1}"
                     id="pb1">
          <af:inputText label="First Name"
                        binding="#{viewScope.SearchUsersBackingBean.it1}"
                        id="it1"/>
          <af:inputText label="Last Name"
                        binding="#{viewScope.SearchUsersBackingBean.it2}"
                        id="it2"/>
          <af:commandButton text="Search Users"
                            binding="#{viewScope.SearchUsersBackingBean.cb1}" id="cb1"
         action="#{viewScope.SearchUsersBackingBean.searchUsersInOIM}" partialTriggers="pc1"/>
          <af:separator binding="#{viewScope.SearchUsersBackingBean.s1}" id="s1"
                        inlineStyle="height:26px;"/>
          <af:panelCollection binding="#{viewScope.SearchUsersBackingBean.pc1}" id="pc1" rendered="#{viewScope.SearchUsersBackingBean.showResults}">
            <af:table var="user" rowBandingInterval="0" value="#{viewScope.SearchUsersBackingBean.usersList}"
                      binding="#{viewScope.SearchUsersBackingBean.t1}" id="t1">
              <af:column sortable="false" headerText="First Name" id="c3">
                <af:outputText value="#{user.firstName}" id="ot5"/>
              </af:column>
              <af:column sortable="false" headerText="Last Name" id="c5">
                <af:outputText value="#{user.lastName}" id="ot3"/>
              </af:column>
              <af:column sortable="false" headerText="User Id" id="c1">
                <af:outputText value="#{user.userId}" id="ot4"/>
              </af:column>
              <af:column sortable="false" headerText="Email" id="c4">
                <af:outputText value="#{user.EMail}" id="ot2"/>
              </af:column>
            </af:table>
          </af:panelCollection>
        </af:panelBox>
      </af:form>
    </af:document>
  </f:view>
  <!--oracle-jdev-comment:auto-binding-backing-bean-name:SearchUsersBackingBean-->
  
</jsp:root>

          16.      Modify Deployment Profile for both Model and View Projects to give meaningful names. 



          17.            Add Model jar as the dependency for View project. 




          18.      Generate the jar files for both model and view using deploy option. 

Steps to deploy the custom app to OIM server:

          19.      Copy the oracle.iam.ui.custom-dev-starter-pack.war file located at $OIM_HOME/server/apps directory to a different directory on the server. 
          20.      Unzip the war file using the below command: 
                      $unzip oracle.iam.ui.custom-dev-starter-pack.war 
          21.      Change directory to the WEB-INF using the below command. 
          22.      Make a new directory called using the below command. 
          23.      FTP the model and view ADF lib jar files to this new directory. 
          24.      Zip the war file using the below command. 
          25.      Copy the latest war file to $OIM_HOME/server/apps 
          26.      Clear the cache and tmp directories located at $DOMAIN_HOME/servers/oim-server1  
          27.      Restart OIM server. 
          28.      Access your new page using the url http://<OIM-HOST>:<OIM-PORT>/identity/faces/searchUsers.jspx
 Voila! now you can search users in OIM using your application instead of the OOTB user search page.