Getting a value from HttpServletRequest.getRemoteUser() in Tomcat without modifying application

13,225

Solution 1

Here is a proof of concept Valve implementation which does it:

import java.io.IOException;
import java.security.Principal;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletException;

import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.realm.GenericPrincipal;
import org.apache.catalina.valves.ValveBase;

public class RemoteUserValve extends ValveBase {

    public RemoteUserValve() {
    }

    @Override
    public void invoke(final Request request, final Response response)
            throws IOException, ServletException {
        final String username = "myUser";
        final String credentials = "credentials";
        final List<String> roles = new ArrayList<String>();

            // Tomcat 7 version
        final Principal principal = new GenericPrincipal(username, 
                            credentials, roles);
            // Tomcat 6 version:
            // final Principal principal = new GenericPrincipal(null, 
            //              username, credentials, roles);


        request.setUserPrincipal(principal);

        getNext().invoke(request, response);
    }

}

(Tested with Tomcat 7.0.21.)

Compile it, put it inside a jar and copy the jar to the apache-tomcat-7.0.21/lib folder. You need to modify the server.xml:

<Host name="localhost"  appBase="webapps"
    unpackWARs="true" autoDeploy="true">

    <Valve className="remoteuservalve.RemoteUserValve" />
...

I suppose it works inside the Engine and Context containers too.

More information:

Solution 2

Use a local, file-based realm for testing. Check your conf/tomcat-users.xml and create roles and users for your application and enable the security constraints in your web.xml. There are good examples in the tomcat-users.xml.

Share:
13,225
Mark
Author by

Mark

Updated on June 04, 2022

Comments

  • Mark
    Mark almost 2 years

    (Using Java 6 and Tomcat 6.)

    Is there a way for me to get HttpServletRequest.getRemoteUser() to return a value in my development environment (i.e. localhost) without needing to modify my application's web.xml file?

    The reason I ask is that the authentication implementation when the app is deployed to a remote environment is handled by a web server and plugged-in tool. Running locally I obviously do not have the plugged-in tool or a separate web server; I just have Tomcat 6. I am trying to avoid adding code to my application merely to support development on my localhost.

    I am hoping there is a modification I can make to the context.xml or server.xml files that will let me set the remote user ID or that will try to pull it from a HTTP header or something.

  • Mark
    Mark over 12 years
    Yes, I have noticed the tomcat-users.xml file and know about adding security constraints within my app's web.xml, but I am asking if there is a way to achieve something similar without modifying actual/real/destined-for-production code; I would be happier modifying just my local server configuration.
  • Mark
    Mark over 12 years
    Thanks for all the information! I created a class like you describe, JAR'd it up and updated the server.xml file. I had to make one change because I am running Tomcat v6.0.20: the GenericPrincipal signature requires a realm so I added final Realm realm = request.getContext().getRealm();. However, it doesn't seem to be having an effect. I've tried updating the context.xml file, too, but again it produced no result. The request's principal and user ID are both null when they reach my application code. Did you perhaps do anything else?
  • palacsint
    palacsint over 12 years
    I just passed null as realm, and it works for me with Tomcat 6.0.20. (See my modifications in the answer.) Are there any exception in your logs?
  • Mark
    Mark over 12 years
    Thanks very much for the help with all this. It turns out I had your valve implemented correctly all along. The reason it didn't work was because I wasn't savvy to the significance of setting the catalina.base JVM property on server start-up. Once I altered the server.xml at that location it all worked perfectly. Thanks again!
  • Edward
    Edward about 11 years
    Hi, palacsint Could you show more details of deployed the remote user through xml file... Thanks!
  • palacsint
    palacsint about 11 years
    @Edward: I'm sorry, I don't have time now for a complete answer. I guess you should ask it as a new question. Drop me a link and I'll check on the weekend if nobody answer it.
  • Edward
    Edward about 11 years
    Thank you very much! palacsint, I have posted here, Thanks ...
  • Adam Michalik
    Adam Michalik over 7 years
    Actually you can forget the GenericPrincipal and implement the simple Principal interface yourself or rip off BasicUserPrincipal from Apache HttpClient.