Monday, January 3, 2011

Fusion Middleware 11g Security - Retrieve Security Groups from ADF 11g

What to do, when you need to access security information directly from ADF 11g application. If there is a requirement to retrieve security groups or system users from WebLogic Security Provider. Every production system is using some kind of LDAP product to store security groups and system users. From what I saw, in the most of the cases, customers are using Active Directory. WebLogic server is configured with Security Provider to point and consume Active Directory connection, deployed ADF application automatically authenticates against configured Security Provider on WebLogic server. Instead of connecting to LDAP server directly, we can use Oracle Platform Security (OPSS) API and retrieve Security Provider information directly through ADF Security connection.

Please read Oracle Fusion Middleware Security blog, in order to get fundamental information about Oracle OPSS - OPSS Sample Application. I did one step forward and explained how you can use Oracle OPSS API inside ADF BC and implement functional requirement to bring security groups. Download sample application - SecurityGroupsCustomApp.zip. My next blog post will explain how to bring system users for selected security group.

Sample application implements Oracle OPSS API logic inside Model project, this allows to build programmatic VO and isolate complex Oracle OPSS logic from ViewController. I have created VO implementation extension IdentityStoreAccess class, this contains Oracle OPSS API methods to connect and retrieve security groups from WebLogic Security Provider:


All complex Oracle OPSS API logic is isolated inside Model project, this allows to expose it to ViewController through standard Data Control, based on programmatic VO:


VO implementation extension class - IdentityStoreAccess, contains method to retrieve role(-s) by specified pattern using Oracle OPSS API. If pattern is specified as wildcard, all available security groups will be retrieved:


This method is using Oracle OPSS SimpleSearchFiler class with ROLE_NAME SearchParameter object.

IdentityStoreAccess class is defined to override base implementation class of programmatic VO:


RolesView programmatic VO is constructed based on security groups collection retrieved from configured WebLogic Security Provider. Connection with WebLogic Security Provider is established through ADF Security connection:


RolesView VO row is populated programmatically, from security groups collection:


When RolesView VO is being initialized, instead of constructing SQL query, overridden executeQueryForCollection method is retrieving information from WebLogic Security Provider. This information is being used to populate programmatic VO:


Programmatic VO is included into AM and allows to consume alternative data source through standard Data Control, there is no difference in ViewController:


ADF Faces table component brings security groups defined inside WebLogic Default Authenticator Provider (for test purpose only). It will retrieve security groups from LDAP exactly in the same way, without any changes for ADF application:


Nice out of the box features provided by ADF Faces table component - filtering and sorting, can be applied for programmatic VO as well:


The same security groups are defined be WebLogic Security Provider:


Default Authenticator in this example is the only one available Security Provider. You can define LDAP connection, security groups will be retrieved as well:

33 comments:

sunil ravinder said...

Hi Andrejus,

I have a OIDProvider (OracleInternetDirectoryProvider) configured to connect an external ldap server. I use he example which you provided but it retrieves users for roles only from the default authenticator. How should I configure or code so that it goes and looks into other providers also.

Thanks,
Sunil

Andrejus Baranovskis said...

Hi,

Make sure your OID provider is set to be first in the list.

Andrejus

sunil ravinder said...

Hi Andrejus,

That seem to work, Thanks. That means the IdentityStoreService is touching the first identitystore with the highest priority. Given that we plan to create two realms, each one with the required OID provider.

I tried it on my IntegratedWeblogicServer by creating two realms and tried to fetch OIDs by realm name

for eg : getIdmStore("myrealm")

it throws

java.lang.UnsupportedOperationException
at oracle.security.jps.internal.idstore.AbstractIdmIdentityStore.getIdmStore(AbstractIdmIdentityStore.java:199)

Moreover, isMultipleRealms() is giving false

Any ideas of why this would be happening ?

Andrejus Baranovskis said...

Hi,

Make sure OID provider is set to be SUFFICIENT. It should pass to second provider, if no success for the first.

Andrejus

sunil ravinder said...

Hi Andrejus,

Thanks for the prompt replies.
Yeah i tried that. I created a SQLAuthenticator as a Provider placed it first (though doesnt matter) and made it sufficient and thereafter i placed DefaultAuthenticator as second with sufficient again. SQLAuthenticators and DefaultAuthenticators roles are showing in the Roles tab of the WLS.

Hard luck.. I tried retrieving the security groups and it gives me DefaultAuthenticator groups only.

We had used to same strategy on a different server with an OID Provider and a DefaultAuthenticator. Does nt pick up OIDProvider's roles.

Any guesses about why this may be happening ?

For debugging purposes we used our own application as well as the sample application provided in the blog.

Thanks,
Sunil

Andrejus Baranovskis said...

Hard to guess, where is your problem...

Try to test the same with ADF Security app.

Andrejus

sunil ravinder said...

Hi Andrejus,

Just found the following posts:

http://download.oracle.com/docs/cd/E12839_01/core.1111/e10043/aptrouble.htm#CIAHHFJI

"The OPSS User and Role API can access data only in the first LDAP authenticator configured in a domain."

Interesting to note is that it also emphasizes LDAP authenticator which are listed on:

http://download.oracle.com/docs/cd/E17904_01/web.1111/e13707/atn.htm#i1216261

May be SQLAuthenticator cannot be used.

Right now we still have nt tried moving the OIDProvider at the top. Will give it a try and let you know.

Thanks,
Sunil

Andrejus Baranovskis said...

Okej, its what I was suspecting. Same behavior is with WebCenter product. It looks this behavior is by design, since its officially documented.

Regards,
Andrejus

sunil ravinder said...

Hi Andrejus,

OIDProvider first (Sufficient) and DefaultAuthenticator second (Sufficient) worked.

Crux..
1. only ldap authenticators are going to be selected
2. the first ldap(and with the highest priority) is going to be selected.

Thanks for the prompt replies...

Sunil

Anonymous said...

Thanks a lot for the wonderful post. It's a lot helpful.

I tried to import the sample application and when I try to connect to the hr database, I am getting the below exception, Can you please help.

avax.naming.NamingException [Root exception is oracle.adf.share.security.ADFSecurityRuntimeException: Unable to initialize the credential store.
]
at oracle.adf.share.jndi.ContextImpl.throwNamingException(ContextImpl.java:573)
at oracle.adf.share.jndi.ContextImpl.saveDocument(ContextImpl.java:845)
at oracle.adf.share.jndi.ContextImpl.save(ContextImpl.java:863)
at oracle.adf.share.jndi.AdfInitialContext.save(AdfInitialContext.java:92)
at oracle.adfinternal.rc.connection.UncloseableContextWrapper.save(UncloseableContextWrapper.java:90)
at oracle.jdeveloper.rescat2.util.ConnectionUtil.invokeOldStyleWizard(ConnectionUtil.java:145)
at oracle.jdeveloper.rescat2.util.ConnectionUtil.showWizard(ConnectionUtil.java:73)
at oracle.jdeveloper.rescat2.nodes.RepositoryRootNode.whenProperties(RepositoryRootNode.java:217)
at oracle.adf.share.dt.AppConnContextMenuListener.onProperties(AppConnContextMenuListener.java:219)
at oracle.adf.share.dt.AppConnContextMenuListener.propertiesEventHandled(AppConnContextMenuListener.java:208)
at oracle.adf.share.dt.AppConnContextMenuListener.handleEvent(AppConnContextMenuListener.java:121)
at oracle.ide.controller.IdeAction.performAction(IdeAction.java:529)
at oracle.ide.controller.IdeAction.actionPerformedImpl(IdeAction.java:884)
at oracle.ide.controller.IdeAction.actionPerformed(IdeAction.java:501)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
at javax.swing.AbstractButton.doClick(AbstractButton.java:357)
at javax.swing.plaf.basic.BasicMenuItemUI.doClick(BasicMenuItemUI.java:1223)
at javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(BasicMenuItemUI.java:1264)
at java.awt.Component.processMouseEvent(Component.java:6267)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3267)
at java.awt.Component.processEvent(Component.java:6032)

Andrejus Baranovskis said...

Hi,

I have verified, sample application connect to HR database without problems. Tested with PS3 and PS2. You can try downloading sample app again.

Thanks,
Andrejus

Morgan said...

Hi Andrejus,

I have downloaded your sample application and it works fine with the integrated weblogic server.

I want to retrieve all the LDAP groups present on our development environment.
I have used your code, but the results displayed are none.

I have checked the order and the control flag(is Sufficient) of the OID Authenticator and Default Authenticator.

The order of providers in myrealm is below.

OAM ID Asserter
OID Authenticator DefaultAuthenticator DefaultIdentityAsserter

Please let me know if I am missing some thing.

Thanks,
Morgan.

tester said...

i am newbie: I am using jdeveloper 10.1.2, what is the HR data base and I found in the "Connections->database" connection called HrDS what it is?

Andrejus Baranovskis said...

This schema is installed together with Oracle XE DB.

Andrejus

tester said...

Hi Andrejus,
I want to have the ability to add and delete groups at run time from my application (authorization) and use active directory for user name and password (authorization), what do u think I have to use to implement that?

Thank you
Belal

Andrejus Baranovskis said...

Try to use OPSS API?

Andrejus

satya@javasoft said...

Hi Andrejus,
My requirement is to fetch the users based on role pattern.Can i acheive it using OPSS user and Role API

Andrejus Baranovskis said...

Yes, this can be achieved with OPSS API.

Andrejus

satya@javasoft said...

Hi Andrejus,
I am trying fetch Roles based on username by using searchRoles() method ,but it is giving me oracle.security.idm.ObjectNotFoundException: No Membership Found

Andrejus Baranovskis said...

Hi,

You should apply filters. Its not the same, but may give you idea: http://andrejusb.blogspot.com/2011/01/fusion-middleware-11g-security-retrieve_08.html

Andrejus

satya@javasoft said...

Hi Andrejus
I have following peace of code in Loginbean (Backing bean)

public String doLogin() {
String un = (String)this.userName.getValue();
byte[] pw = ((String)this.getPassWord().getValue()).getBytes();
FacesContext ctx = FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest)ctx.getExternalContext().getRequest();
CallbackHandler handler = new SimpleCallbackHandler(un, pw);
try {
Subject mySubject = Authentication.login(handler);
ServletAuthentication.runAs(mySubject, request);
ServletAuthentication.generateNewSessionID(request);
String loginUrl = "/adfAuthentication?success_url=/faces" + "/home.jspx";
HttpServletResponse response = (HttpServletResponse)ctx.getExternalContext().getResponse();
sendForward(request, response, loginUrl);
} catch (FailedLoginException fle) {
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Incorrect Username or Password", "An incorrect Username or Password" + " was specified");
ctx.addMessage(null, msg);
} catch (LoginException le) {
reportUnexpectedLoginError("LoginException", le);
}
// start code to check role
ADFContext ctxt = ADFContext.getCurrent();
SecurityContext sctxt = ctxt.getSecurityContext();
System.out.println(sctxt.isUserInRole("userRole"));
//end code to check role
return null;
}
Kindly have a look at the code to check the role(mentioned in comments).I am trying to check the role but it always returning me false.I tried to print the role and it is giving me "anonymous-role".
If i use the same on next page using EL #{securityContext.userInRole['userRole']} it giving me "true"
I am not able to figure out why it is not working in backingBean and working on page(using EL).

Thanks,
Satyendra

Andrejus Baranovskis said...

It might be, ADF Security is not constructed yet, and its too early to check this in Login bean.

Andrejus

Anonymous said...

Hi Andrejus,
I have a OIDProvider (OracleInternetDirectoryProvider) configured to connect an external OID server and this is placed first in order in weblogic. I am using User Name Attribute: as uid in provider specific properties.And in my backing bean i am using the following code to get the oidStore.
try {
JpsContextFactory ctxf = JpsContextFactory.getContextFactory();
JpsContext ctx = ctxf.getContext();

IdentityStoreService storeService = ctx.getServiceInstance(IdentityStoreService.class);
IdentityStore idStore = storeService.getIdmStore();
StoreConfiguration conf = idStore.getStoreConfiguration();
System.out.println((String)conf.getProperty(OIDIdentityStoreFactory.ST_USER_NAME_ATTR));
// conf.setProperty("USER_NAME_ATTR", "uid");
return idStore;
} catch (JpsException e) {
//TODO Add Exception Handling/Logger
e.printStackTrace();
throw new JboException(e.getCause());
} catch (IMException e) {
//TODO Add Exception Handling/Logger
e.printStackTrace();
throw new JboException(e.getCause());
}

But System.out.println((String)conf.getProperty(OIDIdentityStoreFactory.ST_USER_NAME_ATTR)); is printing cn and it is not taking the property configured for OID(i.e uid).I am able to get the other properties configured in weblogic except User Name Attribute .Kindly help me on fixing the issue.

Laurence said...

Hi Andrejus,

Can I use the OPSS API to programatically map enterprise user and groups to application roles?

Many thanks,
Laurence.

Bikram Bhusan Sinha said...

Hi Andrejus,

We have configured OID as the authentication provider in WebLogic and all the security groups and users are coming there. Now how can I bring the groups from there in ADF and map to application roles ? I want to know how can we get there without programmatically ?

Andrejus Baranovskis said...

You need to define roles in ADF jazn-data.xml manually as Enterprise roles and map manually with Application Roles.

You can do it also on Enterprise Manager, after deployment.

Andrejus

nitesh said...

Hi Andrejus,

Thanks for the example.

I have requirement of adding users to existing group/role or new group.

Can You give sample code using OPSS.

Thanks,
Nitesh

Anonymous said...

I have a requirement to get the attributes(properties of a group from the oid. Will this method returrn the attributes of the group as well or is there some other method that i should call, can you let me know the method or call to get the properties of a group.

Thanks for you help
David

Joe Harrison said...

Hi Andrejus,

We are so far not even able to connect to our embedded LDAP without supplying credentials. When we test out the Application Module it prompts for a user and password and then connects. However, when we run the app it fails (as no credentials are provided) "ORA-01005: null password given; logon denied". Is there something that needs to be done to the embedded LDAP to allow a connection, or is there a way to get the proper credentials? I would like to connect using OPSS rather than specifying the specific credentials.

Thanks,

Joe

Andrejus Baranovskis said...

It might be your application is corrupted. Try to test with new application.

Andrejus

SreeVardhan said...

Hi Andrejus,
How to get all the groups from all the providers set in the weblogic console. I tried to get a role from external provider that was already set in the console but its failing with an exception 'ObjectNotFoundException'.

Thank you.

Andrejus Baranovskis said...

Hi,

OPSS API retrieves only first provider in the list, you need to reorder. Also all providers must be set as SUFFICIENT.

You can join multiple providers by configuring libOVD support on WLS domain.

Andrejus

Ghazi Hakim said...

Hi Andrejus,
Thank you it was very helpful.

Now I have a webcenter application.
How can I get the permissions (create,delete,grant,manage,personalize,update,view) of each security group of my jspx pages ?

Thank you again