Wednesday, October 17, 2012

ADF Essentials Security Implementation for Glassfish Deployment

ADF Essentials includes all the key ADF technologies, only one is missing - ADF Security. This is related to ADF Security technical implementation dependency on WebLogic security. However, lack of ADF Security support is not a show stopper - we can enable JAAS security model. This would protect page resources from ADF application, but not ADF Task Flows with Fragments. One of the most common ADF architectures nowadays - use of ADF Task Flows with Fragments through dynamic regions based on single page. This means security implementation to protect ADF Task Flows with Fragments, when rendered through dynamic region is very important.

In this post I will provide solutions, implemented in the sample application - MultiTaskFlowApp_gfsec.zip for:

1. Configuring JAAS security for ADF application
2. Configuring ADF application for Glassfish security
3. Restricting access to ADF Task Flows with Fragments

Sample application contains SecurityController class - custom class, responsible to check if task flow can be accessed. Logic is pretty simple - we check current dynamic region task flow address, compare it along with a security check (globalaccess role). This is simplified example, in real life most likely you would retrieve mapping between task flow and security role from the database:


Now the key part - from where this logic is invoked. It is invoked from task flow activation property (conditional activation). This means, dynamic region will be activated only if task flow will be viewable (security access is granted) based on the custom security logic from our method above:


This is how we can control ADF Task Flow with Fragments access.

Now let's take a look how security infrastructure is configured for deployment. Firstly you need to define JAAS security constraint in web.xml:


As you can see here, all pages (/faces/*) are restricted to be accessed only for authorized roles. These roles are mapped with groups. Groups are defined on Glassfish server. This is the same concept as with WebLogic, only that we need to use glassfish-web.xml (create it manually) configuration file in WEB-INF where roles are mapped with groups:


We can test it now - login as redsam (GlobalUser):


Open task flow for Departments:


Login now as sking (RegionalUser):


This user doesn't have access to the Departments task flow, task flow will not be activated as per our security check implementation:


You can create local user in Glassfish, just in the same way as you do in WebLogic - go to file realm and press Manage Users:


You can manage users from here:

29 comments:

  1. hi,

    what does it take to make this application run back on WebLogic?
    It's a bit boring testing applications on Glassfish...
    So i'd prefer all-stage-development in JDeveloper, then final deployment to Glassfish.
    I followed to Shay Shmeltser blog's recommendation on deployement to Glasssfish and reversed it.
    During runtime i get the error:
    While trying to lookup 'jdbc.ncsDS'
    didn't find subcontext 'jdbc'.Resolved
    What might cause it?
    i set for both DeployPlatform

    ReplyDelete
  2. Agree 100%.

    This error means Data Source is not defined on on your server, you must configure it.

    Andrejus

    ReplyDelete
  3. Andrejus,
    i have an application running in weblogic with shared libraries. From JDev i deploy those as shared libraries.
    Is it possible in Glassfish?
    Tks.

    ReplyDelete
  4. Andrejus did you test the shared libraries in Glassfish?

    ReplyDelete
  5. Not yet - this is on my list. Quite busy... :)

    Andrejus

    ReplyDelete
  6. Hi Andrejus,
    thanks for the post.
    for the login page is it the same as shown with weblogic:

    public String doLogin1() {
    String un = (String)login1.getValue();
    String pass;
    pass = (String)password1.getValue();
    byte[] pw = pass.getBytes();
    FacesContext ctx = FacesContext.getCurrentInstance();

    HttpServletRequest request = (HttpServletRequest)ctx.getExternalContext().getRequest();
    try {
    Subject subject = Authentication.login(new URLCallbackHandler(un, pw));
    weblogic.servlet.security.ServletAuthentication.runAs(subject, request);

    String loginUrl = "/adfAuthentication?success_url=/faces/index.jsf";
    //String loginUrl = "/adfAuthentication?success_url=/faces/main.jsf";

    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");
    //setPassword(null);
    //setUser(null);
    ctx.addMessage(null, msg);
    } catch (LoginException le) {
    reportUnexpectedLoginError("LoginException", le);
    }

    return null;
    }

    ReplyDelete
  7. hi andrejus,

    when I login using Glassfish server in first time, the login page appear but when i want to login with another user i refresh the page but the login window did not appear!
    how can i login with another user?

    Thanks

    ReplyDelete
  8. Hello Andrejus,

    about the security in ADF Essentials.
    We have a non functional requirement to restrict access for users not only to some page or region but also to the records of the table.
    For that reason we use Oracle database context solution, the context is set depending by the user, which is logged in. We use another framework, but are thinking about migration to ADF.
    What solution do You suggest to use in ADF for solving restriction by records question?

    Thank You.

    ReplyDelete
  9. Hi,

    You can set DB proxy user from ADF BC and continue using DB security. Read more: http://andrejusb.blogspot.ca/2012/03/testing-adf-bc-proxy-user-db-connection.html

    Andrejus

    ReplyDelete
  10. Hi,

    thank You for great post!

    Don't You recommend to write own security module for Essentials?

    If You keep and manage users and roles in the glassfish server, every time administrator wants to manage security rights, he has to do it in glassfish console which is not so convenient than to do it directly in the application.
    In some other frameworks (i.e. Oracle Forms) we have own security modules, where You can administrate users, roles, functions that can be executed bu role, etc. Application administrator can manage them directly in the application.
    What would be Your recommendation: write own security module or use some other, for example, to use user and roles administration in Glassfish like in Your example?

    Thank You.

    ReplyDelete
  11. Hi,

    There are two things - enforce security and manager users/roles. Here I describe how to enforce security. Users and roles can be stored in DB, then you need to define SQL Authenticator. Users/Roles can be managed then in similar way as it is done in Forms.

    Andrejus

    ReplyDelete
  12. Hi Andrejus,

    Great Post.

    But I was wondering if i am suppose to give anonymous access to a page say login .. how can i define these? because i would like to use form based authentication.

    ReplyDelete
  13. Yes, if you want to define login page, it must be granted with anonymous access. You can define new security constrain in web.xml.

    Andrejus

    ReplyDelete
  14. Do you know what is the Glassfish equivalent of the Java code to authenticate against the container? I would like to implement an additional login form in the template header of my web app's pages - and such a login is only possible in ADF by doing the login programmatically in a backing bean method.
    Can this even be done with Glassfish?

    There is an API called ProgrammaticLogin - but I'm not convinced that's what I need to work with.

    Thanks,
    Darren

    ReplyDelete
  15. Hi,

    I have a page where I have buttons Create, Update and Delete. I want to enable those buttons only if the user logged in as Admin in ADF running on Glassfish Open Source edition. I am new to this world. If you can guide me then that will be great.

    Thanks,
    Mehabub

    ReplyDelete
  16. Thx Andrejus. Just a quick question:
    Where should I change security realm from file to jdbcrealm. I have already configured it under glassfish server.

    ReplyDelete
  17. Hi Andrejus,

    We have a specific requirement in which user wants to buy single Oracle EBS(R12) license and wants to build a custom login page using ADF so as to authenticate multiple users on top of single license and capture the login info. Do you have any idea about how to implement this particular req.

    Thanks in advance,
    Mohit

    ReplyDelete

  18. Hi andrejus

    Could please re upload the Application as it is no longer exist

    "The requested URL /files/MultiTaskFlowApp_gfsec.zip was not found on this server"

    ReplyDelete
  19. I cant find this sample anymore, sorry.

    Andrejus

    ReplyDelete
  20. Hi Andrejous,
    I found your sample at https://code.google.com/archive/p/jdevsamples/downloads?page=6

    Timo

    ReplyDelete
  21. Thanks, this will save me time to allow update for samples older than 2014 year.

    Regards,
    Andrejus

    ReplyDelete
  22. Hi Andrejus,
    thanks to Timo now I can analize your example.
    Unfortunately I cannot run it:
    - I've tried to use Glassfish 3.1 (JDK 1.7.0_79, ADF Essentials 12.1.3) but cannot deploy, since I use JDeveloper12c and I obtain a UnsupportedClassVersionError on oracle.adfinternal.view.faces.activedata.AdsServlet)

    - I've tried to use Glassfish 4.1 (JDK 1.8.0_101, ADF Essentials 12.2.1.0.0) but I cannot run the application, since I obtain a NoClassDefFoundError on oracle/adf/share/merge/ADFMergeException)

    - I've tried to use Glassfish 4.1.1 (JDK 1.8.0_101, ADF Essentials 12.2.1), but I cannot run the application, since I obtain a NoClassDefFoundError: Could not initialize class oracle.adf.share.security.identitymanagement.UserProfile;

    Basically could tou tell me what version of JDeveloper - Glassfish (possibly with the JDK) - ADF Essentials have you used?

    Thanks a lot for all you share with us,
    Piero

    ReplyDelete
  23. Here a right combination

    Jdeveloper 11.2.4.0 (using JDK 1.6.0_24)
    Glassfish 3.1.2.2 (JDK 1.8.0_51)
    ADF Essentials 11.1.2.4

    Regards,
    Piero

    ReplyDelete
  24. I'm using JDeveloper 12.2.1, Glassfish 4.1.1, ADF Essentials 12.2.1;
    I obtained
    NoClassDefFoundError: Could not initialize class oracle.adf.share.security.identitymanagement.UserProfile
    Then I discover the UserProfile class initialize a MDS session, that can't exists in GlassFish;

    My solution:
    - Decompile the class
    - Rewrite it preserving package name and all public methods
    - Create a new jar
    - Place it in /lib directory

    I restart the server 5 times to check the class conflict (same class exists in adf-share-ca.jar and my jar) and all 5 times I don't obtain the error

    ReplyDelete
  25. Hello Andrew
    I am very interested in the ADF Securirity on Glassfish. Regularly follow your blog which is an excellent and very useful, but I see that there is no examples, is there a possibility to find them to download them.
    Greetings,
    Drasko

    ReplyDelete
  26. Recently working mostly on normal ADF, thats why no posts related to ADF Essentials.

    Andrejus

    ReplyDelete