Forum Stats

  • 3,855,178 Users
  • 2,264,465 Discussions
  • 7,905,912 Comments

Discussions

Authorization, JNDI, JNI, JAAS - views on a problem.

843811
843811 Member Posts: 49,851 Green Ribbon
Hiya,

It appears that JAAS only authenticates and authorizes to whomever has initiated the JVM on the server machine. I'm trying to develop an application that is web-based, and allows the user to view documents anywhere on the network (accessible from the server). Of course, the user may not have the appropriate permissions to view a document, therefore we looked at JAAS to provide some authentication/authorization for us.

This has not proved successful, as mentioned above.

This leads us to the conclusion that we may have to write a JNI native app that attempts to read/open the document on the target machine, where the document is physically located, with the username/password of the person at the client. If unsuccessful it throws an exception, otherwise it allows the user to view the document.

I'm looking for views on this. Given the above, do you believe this might be the best way for the moment? Of course, a JNI app would need to be written for each platform and it would need to be registered with JNDI for easy accessiblility from our Java Server application.

Any thoughts would be appreciated.

Yours


David.

Comments

  • 843811
    843811 Member Posts: 49,851 Green Ribbon
    Hi David,

    It can be very well done through JNDI, Netscape Directory Server.

    Here with I am giving you a sample code which was tested under Netscape Directory server 4.13, JNDI and with Iplanet Web Server.
    It will ask for Login Page, and then it will invoke the corresponding HTML page. But you can make changes over there as per your request. Since you can keep all the common things in an LDAP server ie in Netscape Directory server.

    Here is the steps for it.


    DESCRIPTION:
    I am trying to use LDAP to control access to a HTML page. I want an authentication
    box to pop up, allowing the user to authenticate to the HTML page through a LDAP server.
    If they succesfully authenticate, I need to check their username against a list
    of valid usernames that's stored in a database, then give access to the page
    based on that list. How can I implement this solution?


    SOLUTION:

    The best way is to use Basic Authentication solution with JNDI and LDAP server,
    Netscape Directory server(for example) with a simple servlet program. Java Naming
    and Directory Interface (JNDI) API is standardized, and enable to use different
    directory services such as Netscape Directory server. LDAP server can be used
    for storing some common data's used in the sample solution.


    It can be done through a servlet to check the user and its password which is
    stored in the LDAP server.

    In order to demonstrate a sample solution, I will use the Netscape Directory
    Server 4.13 as the LDAP server, which is loaded my own LDIF file with customized
    attributes. The basic authentication algorithm will be used in this sample
    solution.


    The following steps are to implement this sample solution:

    1. Creating our own LDAP data Interchange format (LDIF) file.
    2. Loading(Import) the Ldif file in Netscape Directory Server.
    3. Creation of user schema files for customized attributes.
    4. Load the user schema files in the Netscape Directory Server.
    5. Restart the Directory Server
    6. A simple servlet program for basic authentication.
    7. A sample HTML file is given last, used in servlet program.


    Here are the detail description of the above steps:

    STEP 1: Creating our own LDAP data Interchange format (LDIF) file:

    Here is the LDIF (LDAP data Interchange format) file is a text based format used to work
    on LDAP data, with both our application and end users.

    Through this LDIF file, I am having an attribute "customerid: timb" for which I will
    be preparing the authentication, which will have its own password
    "userpassword: bakrudeen", through which it can be maintained in a common place.
    Here again in the same LDIF file, other information related to the "customerid: timb"
    such as common name "cn: Tim Briggs", sur name "sn: Briggs" etc are maintained.


    The data in LDAP is organized in a tree, called a Directory Information tree(DIT).
    Each leaf in DIT is called an entry. The first entry in DIT is called the root entry.

    Here is a sample LDIF File which is used in our sample solution:-


    Here the DIT is maintained in such a way data is organized in LDAP, is fairly simple. In this
    sample we store all of our entries in a common root o=fedup.com, with the following branches
    Customers - Customer Entries with " customer id: timb" , userpassword: bakrudeen, and other
    information related to this customer is kept in a common place.


    dn: uid=timb,ou=Customers,o=fedup.com
    changetype:add
    objectclass: customer
    objectclass: inetorgperson
    objectclass: organizationalPerson
    objectclass: person
    objectclass: top
    cn: Tim Briggs
    uid: timb
    givenname: Tim
    customerid: timb
    sn: Briggs
    facsimiletelephonenumber: 4101
    telephonenumber: 4145
    creatorsname: uid=admin,ou=Administrators,ou=TopologyManagement,o=NetscapeRoot
    createtimestamp: 20000501084001Z
    aci: (target="ldap:///uid=timb,ou=Customers,o=fedup.com")(targetattr="*")(version 3.0; acl "unknown"; allow (all)(userdn = "ldap:///anyone");)
    ou: Customers
    mail:
    userpassword: bakrudeen
    modifiersname: uid=admin,ou=Administrators,ou=TopologyManagement,o=NetscapeRoot
    modifytimestamp: 20000605084001Z


    STEP 2: Loading(Import) the Ldif file in Netscape Directory Server:-

    Once after creating the above sample LDIF File, it should be added in Netscape Directory Server.
    It should be imported in order to add the neccessary atributes in the Netscape Directory server,
    so that we can make use of the Common data.

    Steps for Importing the LDIF file in the Directory Server:-

    1) Create an instance of the Directory Server.
    2) Bind it to the different port with different organizational unit
    (Here in this program, it is 1124).
    3) Press the Configuration from the menu.
    4) Then select import from the Console menu.
    5) Choose the LDIF file you are going to import.
    6) There also you have to provide a file for rejected entries, ie it will list all the entries
    which is not added while loading.


    STEP 3: Creation of our own USER SCHEMA Files:-

    It is necessary for adding the attributes which are not defined in the
    Netscape directory server. In the above, customerid which is defined in ldif
    file is not existing in the directory server.

    Here is the Schema file for attributes:(ie for defining for eg customer id).


    The name of the file is slapd.user_at.conf:-

    attribute customerid customerid-oid cis single
    attribute packageid packageid-oid cis single
    attribute receivedate receivedate-oid cis single
    attribute shipdate shipdate-oid cis single
    attribute shipperid shipperid-oid dn single
    attribute receiveid receiveid-oid dn single
    #Java Attributes
    # Schema for storing java objects and java object references

    attribute javaClassName 1.3.6.1.4.1.42.2.27.4.1.1 ces single
    attribute javaCodebase 1.3.6.1.4.1.42.2.27.4.1.6 ces
    attribute javaSerializedData 1.3.6.1.4.1.42.2.27.4.1.7 bin single
    attribute javaRemoteLocation 1.3.6.1.4.1.42.2.27.4.1.8 ces single
    attribute javaFactory 1.3.6.1.4.1.42.2.27.4.1.4 ces single
    attribute javaReferenceAddress 1.3.6.1.4.1.42.2.27.4.1.3 ces


    Here is Schema file for your own object classes:-

    The name of the file is Slapd.user_oc.conf:-

    In the similar way as above there are no "customer" class in the object classes
    defined in the LDAP, so we will have to create our own "customer" Object class.
    Also it extends inetOrgPerson to add some new attributes such as "customerid".
    The object class of an entry specifies what attributes are required and what
    attributes are allowed in a particular entry.

    Also for eg, Package classes in the object class is created.

    Here is the sample file for creating the above:-

    objectclass package
    oid package-oid
    superior top
    requires
    packageid,
    receiveid,
    shipdate,
    shipperid
    allows
    description,
    ou,
    receivedate

    objectclass customer
    oid customer-oid
    superior inetorgperson
    requires
    customerid
    allows
    c

    #JAVA Schema
    # Schema for storing java objects and java object references

    objectclass javaContainer
    oid 1.3.6.1.4.1.42.2.27.4.2.1
    superior top
    requires
    cn

    objectclass javaObject
    oid 1.3.6.1.4.1.42.2.27.4.2.4
    superior top
    requires
    javaClassName
    allows
    javaCodebase

    objectclass javaSerializedObject
    oid 1.3.6.1.4.1.42.2.27.4.2.5
    superior javaObject
    requires
    javaSerializedData

    objectclass javaRemoteObject
    oid 1.3.6.1.4.1.42.2.27.4.2.6
    superior javaObject
    requires
    javaRemoteLocation

    objectclass javaNamingReference
    oid 1.3.6.1.4.1.42.2.27.4.2.7
    superior javaObject
    requires
    javaReferenceAddress,
    javaFactory



    STEP 4: Loading the USER SCHEMA files in Directory Server:-

    All the attributes created above should be added to the corresponding directory server,
    in order to make it as a common attribute.


    Steps for adding the User Schema files to the Directory Server:-

    1. Copy the above user schema files to the appropriate instance of Netscape Directory Server
    created above so that the existing LDIF file which is used in the Netscape directory
    server is not appended or overwritten.

    2. For eg, put it in "NetscapeServer/slapd-HostName/config" to replace the empty
    files "slapd.user_at.conf" and "slapd.user_oc.conf" by default.

    3. Then restart the Directory Server.


    STEP 5: Simple Servlet Program for BASIC AUTHENTICATION.


    Here is the simple servlet program for Basic Authentication:-

    Here the way the LDAP authentication works is by attempting to the server with a
    DN and a password. No user in their right mind will remember their DN, so we use
    some other attribute such as user-id. Then we search in the LDAP server to find
    an entry that contains the attribute. Here we are maintaining SUBTREE_SCOPE using
    JNDI, which starts its search starting from the base entry, and searches
    everything below it including the base entry. Also I am maintaining Global
    variables for LDAP setting.


    // Importing the necessary Packages

    import java.io.*;
    import java.util.*;

    import javax.servlet.*;
    import javax.servlet.http.*;

    import javax.naming.*;
    import javax.naming.directory.*;

    public class AuthServ extends HttpServlet {

    // Here are our global variables of our LDAP Settings.


    public static String MY_CUSTOMER_BASE = "ou=Customers,o=fedup.com";
    public static String INITCTX = "com.sun.jndi.ldap.LdapCtxFactory";
    public static int MY_PORT = 1124;
    public static String MY_HOST = "ldap://sundts1.india.sun.com:" + MY_PORT;
    public static String MY_MGR = "cn=Directory Manager";
    public static String MY_PWD = "password";
    public static String MY_SEARCHBASE = "o=fedup.com";
    Hashtable env = new Hashtable();


    // Using the Get Method of Servlet


    public void doGet(HttpServletRequest req, HttpServletResponse res)
    throws ServletException, IOException {
    res.setContentType("text/html");



    // To Check to See if there is any data in the "Authorization" Http header from the browser.

    // If not it will prompt for username and password.


    String auth = req.getHeader("Authorization");

    // Do we allow the user


    if (!allowedUser(auth) ) {

    // Not Allowed, so report unauthorized
    res.setStatus(res.SC_UNAUTHORIZED);
    res.setHeader("WWW-Authenticate", "BASIC realm=\"users\"");

    }

    // User is allowed in


    else

    {


    // Using SSI to include and display the content of a Simple HTML Page


    RequestDispatcher rd= this.getServletContext().getRequestDispatcher("/auth.html");
    rd.include(req,res);

    }
    }


    // This method checks to see whether the user exist in the LDAP database.


    protected boolean allowedUser(String auth) throws IOException {

    Hashtable env = new Hashtable();
    boolean status = false;

    try {

    // No Authorization


    if (auth == null) return false;

    // Basic Authentication is Handled, Other possibilities are MD5 hash or SSL Certificates.


    if (!auth.toUpperCase().startsWith("BASIC ")) {
    return false; //only do BASIC
    }

    // Get encoded user and password, comes after BASIC


    String userpassEncoded = auth.substring(6);

    // Decode it, using any base 64 decoder


    sun.misc.BASE64Decoder dec = new sun.misc.BASE64Decoder();
    String userpassDecoded = new String(dec.decodeBuffer(userpassEncoded));
    StringTokenizer st = new StringTokenizer(userpassDecoded,":");
    String customerid = st.nextToken();
    String pwd = st.nextToken();

    /*
    Please Note:

    LDAP Authentication works by attempting to bind to the server with a DN and a password.
    No user will remember their DN so we use some other attribute such as user-id.
    Then we search in the LDAP server to find an entry in the LDAP server to find an entry
    that contains the attribute.
    For a Secure System, we should use an attribute that will be unique per entry such as
    uid, in our case the "customerid" attribute.

    */

    // Prepare for context

    env.put(Context.INITIAL_CONTEXT_FACTORY, INITCTX);
    env.put(Context.PROVIDER_URL, MY_HOST);

    // Get a reference to a directory context

    DirContext ctx = new InitialDirContext(env);

    // Specify the scope of the search

    SearchControls constraints = new SearchControls();
    constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);

    // Perform the actual search

    // We give it a searchbase, a filter and the constraints

    // containing the scope of the search


    NamingEnumeration results =
    ctx.search(MY_CUSTOMER_BASE, "(customerid=" + customerid + ")", constraints);

    String dn = null;


    /*
    If it does not throw an exception,

    then it is considered to be an Successful Authentication

    */


    // Now step through the search results


    while (results != null && results.hasMore()) {
    SearchResult sr = (SearchResult) results.next();
    dn = sr.getName() + "," + MY_CUSTOMER_BASE;
    }

    env.put(Context.SECURITY_AUTHENTICATION, "simple");
    env.put(Context.SECURITY_PRINCIPAL, dn);
    env.put(Context.SECURITY_CREDENTIALS, pwd);

    try {
    DirContext ctx2 = new InitialDirContext(env);
    status = true;
    } catch (AuthenticationException e) {
    log(e.toString());
    }
    } catch (NamingException x) {
    log(x.toString());
    }
    return status;
    }
    }


    STEP 6: Simple HTML file used in Servlet Program:-


    Here is the Simple HTML File we are including in RequestDispatcher of the above program:-


    <html>
    <head>
    <title> Authorisation</title>
    </head>

    <body>
    <h1> Your Authorisation is Successful </h1>
    </body>
    </html>


    I hope this will help you.

    Thanks
    Bakrudeen
    Technical Support Engineer
    Sun MicroSystems Inc, India


This discussion has been closed.