Wednesday, November 14, 2012

X509 Fallback to Form

OAM 11G does not provide an out of box solution for falling back to FORM authentication if X509 Certificate is not available or if the certificate is not accepted by the user. I have seen this requirement coming from customers and found a solution after brainstorming with my colleagues (special thanks to Chris Johnson and Brian Eidelman). The solution is not very difficult, though it needs some additional configurations and coding.

It should be noted that this solution is not for the use case where the user's authentication is rejected due to an invalid certificate by OAM and then the user needs to fallback to a FORM for another authentication attempt.


The solution needs configuring a X509 (Cert) Authentication Scheme and a Form Authentication Scheme. The real resource needs to be protected by the Cert Authentication scheme whereas a secondary resource needs to be protected by the Form Authentication scheme. The configuration of the Form Authentication is standard whereas the configuration of the Cert Authentication scheme is little different. The Challenge URL of the Cert Authentication scheme is a custom credential collector (different than the out of the box configuration). This custom credential collector is a servlet and needs to be deployed to the OAM managed server(s).
All the necessary configurations in Weblogic and OAM are configured with SSL and make sure that the default out of box X509 Authentication is working as desired. 
Make sure while configuring the SSL for the OAM Server in the Weblogic Configuration (Weblogic-Domain->Environment->Servers->oam_server->SSL->Advanced), in the Two Way Client Cert Behavior, you select “Client Certs Requested but Not Enforced”.


If the OAM server is front ended with OHS/Apache please read the following post about how to offload SSL with reference to a Weblogic server:
And also make sure that the directive "SSLVerifyClient" is set to optional in the httpd.conf file.
OAM Configuration
Authentication Scheme Configuration:

Create a new Authentication Scheme, named X509CustomCred as below:

Challenge Method: X509
Challenge Redirect URL: /oam/server
Authentication Module: X509Plugin
The Challenge URL is the URL for the custom credential collector (a Servlet) and as follows:

(In this post, it is assumed that the Weblogic’s SSL port is 14101)

A snapshot of Authentication scheme will look like:


Configure X509Plugin Authentication Module:

With this plug-in, the root and sub CA certificates must be added to the DOMAIN_HOME/config/fmwconfig/amtruststore because the X509CredentialExtractor plug-in loads certificates from this location.
Also, make sure about the following:

Go to System Configuration->Custom Authentication Module->X509Plugin

Under stepX509:

set KEY_CERTIFICATE_ATTRIBUTE_TO_EXTRACT to the certificate attribute to be used to bind the public key (attributes within subject, for example: subject.DN, issuer.DN, subject.EMAIL etc. or within subjectAltName as mentioned in ).

Under stepUI:

If the Identity Store is different than the default Identity Store, configure this as required.

Policy Configuration

The target resource is protected by the X509CustomCred Authentication Scheme (created above).

We will configure another resource, for example, a Resource URL /form/*, protected by the default LDAPScheme. Both the X509CustomCred and the LDAPScheme should be at the same Authentication Level.

A snapshot of  the Policy for this secondary resource will look like:

Custom Credential Collector

Deployment descriptor:

The custom credential collector is a Servlet and deployed as a warfile. This is a Servlet where OAM redirects to collect the credentials.
For the Challenge URL as mentioned above, the servlet-mapping of the deployment descriptor (web.xml) will look like:

And the deployment descriptor for the warfile, that is, the context root of the weblogic.xml will look like:


The logic of the Servlet is as follows:
If the X500Principal is available then we forward the request to “/oam/server/auth_cred_submit”. If it is not available then we redirect to a page which is protected by a default LDAPScheme with a FORM Challenge.

A typical code can be implemented like this:

public void doGet(HttpServletRequest request,   HttpServletResponse response) throws ServletException,  IOException {
try {
         X509Certificate  x509Cert[] = (X509Certificate[]) request.getAttribute       ( "javax.servlet.request.X509Certificate");
        String x500Prin = x509Cert[0].getSubjectX500Principal().getName();
        if(x500Prin != null) {
                doPost(request, response); 
      } catch (Exception e)     {
            String target = request.getParameter("resource_url");           
            String  redirectURL = formURL  + "?TARGET=" + target;

protected void doPost(HttpServletRequest request, HttpServletResponse response)  throws ServletException, IOException   {
        String authCredServletPath = "/server/auth_cred_submit";              
        ServletContext sc1 = getServletContext();
        ServletContext sc2 = sc1.getContext("/oam");
        RequestDispatcher rd = sc2.getRequestDispatcher(authCredServletPath);       
        rd.forward(request, response);


In the doGet method, the String “formURL” is the URL of the resource protected by the LDAPScheme. This resource can be a JSP (refer to Sample JSP for Redirection to Original Resource), a Servlet or may be a simple HTML with Javascript. This page will extract the TARGET from the query parameter which is the original “resource_url” and will redirect to that.
For example, if:

The original resource URL (the original target) is:  (protected by the Custom Credential Collector with X509 Challenge)

The formURL  is: (protected by the LDAPScheme with FORM Challenge)

The redirectURL will be formed as:

Sample JSP (redirect.jsp as above) for Redirection to Original Resource

JSP Code:

  String query = request.getQueryString();
  String target = null;
  String decodedTarget = null;
  int tokenN = -1;
  if (null != query) {
   tokenN = query.indexOf("TARGET=");
    if (-1 != tokenN)
    target = query.substring (tokenN + "TARGET=".length());
    if (null != target)      
     decodedTarget =;
    if(decodedTarget != null) 
         out.println ("No Target to redirect");
  else {
  out.println ("No Query found to extract Target");


The user tries to access the resource which is protected by the authentication scheme X509CustomCred. 

If the browser has the certificate installed, the user is prompted by an X509 Certificate and if the user accepts it, the user can access the resource and this is the desired behavior with X509.

If the user does not accept it or if the browser does not have the certificate:
  1. The user will be redirected to a secondary resource which is protected by a HTML Form with a TARGET query parameter of the original resource URL. 
  2. The user enters username and password and hits the Submit button.
  3. Upon successful authentication and authorization, the secondary resource ( it may be JSP, a Servlet or a HTML page with javascript)  will extract the TARGET query parameter of the original resource URL and will redirect to that.
  4. The user can access the original resource URL.


  1. Debasish ,
    Excellent post on the PIV/Form Auth, Can you explain where exactly we need to put the code for JSP Code (Sample JSP for Redirection to Original Resource)


  2. Thanks for the question, I just updated the post. The secondary resource can be the JSP page. Remember it can also be a HTML page with javascript and also may be a Servlet.

  3. Debasish,

    Please help on this multiple redirect loop
    I am successfully tested up to the step 3 and not forwarding to step 4 (It redirect to Redirect.jsp 5 times before i got the below error on the webpage).
    original resource : welcome_source.html(protected with https://:14101/customcred/getcreds)
    Redirect jsp : http://:7777/Redirect/Redirect.jsp(deployed on Admin server and proxies thru OHS, and protected with form AuthN)

    SetHandler weblogic-handler
    WebLogicPort 7001
    DebugConfigInfo ON

    The webpage at https://:14101/customcred/getcreds?authn_try_count=0&contextType=external&challenge_url=https%3A%2F%2Fiamps9%3A14101%2Fcustomcred%2Fgetcreds&request_id=4649136659505797369&locale=en_US&resource_url=http%253A%252F%252F%253A7777%252Fwelcome_source.html has resulted in too many redirects. Clearing your cookies for this site or allowing third-party cookies may fix the problem. If not, it is possibly a server configuration issue and not a problem with your computer.
    5 times it iterated in Redirect.jsp


  4. Make sure that both the resources are protected by auth schemes of same authentication levels. You can also test it by accessing the redirect.jsp page first using FORM credentials (make sure you don't invoke sendRedirect when TARGET is missing and print something as per the sample code)and then access the welcome_source.html page. You can also test it reversely, that is, accessing the welcome_resource.html using a valid X509 and then access the redirect.jsp resource. That will verify your configuration.

    Another thing, depending on the browser sometimes you may need to URL-Encoding/Decoding properly. That means you may need to tweak the code where URL encoding and decoding is happening.

    Best of luck!

  5. Hi,

    I am looking to do something similar with the kerberos fallback.
    We currently have oam configured with kerberos and this works fine.

    We however have to cater for users who are not in the kerberos domain and so wish to provide a form based fallback (mainly the /oam/pages/login.jsp) rather than the browser based BASIC authentication popup which we are currently shown.

    can we configure something of a similar nature for the kerberos authentication scheme?

  6. Kerberos fallback to forms is difficult if not impossible to reliable do because of a limitation of the HTTP and "Negotiate" authentication protocol and there is no simple way around it.

    Chris discussed a way to avoid the pop-up and still get WNA to work under OAM 10g with some customization of the login process some time ago in a blog post at:

    However, we've heard others report that newer versions of the JDK didn't work the same way so no guarantees that this will work.


Note: Only a member of this blog may post a comment.