Solved

How to limit MOD_REWRITE to initial request - pass through on redirect ?

Posted on 2004-10-22
436 Views
Last Modified: 2010-05-18
Hi All,

Am I using mod_rewrite correctly ?
Or should I be pursuing some other solution ?

* I'd like to provide basic authentication/access control to static pages/files in apache.
* Currently our security/users/ACP etc. are all managed by an application in WebSphere/DB2.  I don't want to duplicate all this information for Apache -- though eventually we will move to LDAP and one central store.

** My hope is to use mod_rewrite (for the short-term to):
1) redirect all URL requests for a certain directory to a servlet;  with the original requested url now appended as a parameter to the servlet:
http://myservlet/?url=http://myOrigURL

2) the servlet checks if the user is logged in (websphere login) -- if not they are redirected to the right forms etc.etc. if successful -- the user is then redirected (response.sendRedirect()) back to the original URL they requested.

3) I figured I could use a condition:
RewriteCond %{REMOTE_ADDR} !localHost

To make sure I'm NOT trapped into an endless URL redirect situation.
However, my servlet response.sendRedirect preserves the original "requesters" IP -- so I can't tell if the request is coming from:
   a) my servlet using a redirect or
   b) directly from an unauthenticated client ?

Servlet - "forward" commands can only forward within the context of the servlet container (i.e. cannot forward to an external URL ?)

My Question:
** Can mod_rewrite work in this situation -- or am I wasting time ??
** Is there some kind of production worthy apache module (currently looking at mod_auth_any) that can help me delegate apache authentication to existing servlet code I have ??

Hope someone can help me out.

Please see rewrite rules I'm using below....


Thanks

Frank

From....MyMOD_REWRITE.conf:
RewriteEngine on
RewriteLog "D:\WebSphere\HTTPServer\logs\rewrite.log"
RewriteLogLevel 4
RewriteCond %{REMMOTE_ADDR} !httpServerHost [OR]
RewriteCond %{REMMOTE_ADDR} !xxx.xxx.xxx.xxx
RewriteRule ^(.*)/download/(.*) http://host/webapp/servlet/forceLoginDirect?urlKey=%{REQUEST_URI}
##NOTE: Tried appending -- but don't really grok the following:
##[R]    and [R,L]
##[PT]  and  [PT,L]
##[P]    and  [P,L]
## Still URL loops endlessly on redirect from sevlet because
##%{REMOTE_ADDR} does not become the httpServerHost IP on redirect.
--------------------------

Note: These rules are specifed at the server level (i.e. NOT directory level)
But they are within context of a VirtualHost:

From....httpd.conf:
<VirtualHost xxx.xxx.xxx.xxx>
      ServerName www.ourdomain.com
      Include E:\WebSphere\HTTPServer\conf\MyMOD_REWRITE.conf
      Alias      /doc                  "E:\WebSphere\App/web/doc"
      etc.etc.
</VirtualHost>


I'd be eternally grateful for ANY feedback/thoughts.

Hope to hear from someone soon.....
Thanks
0
Question by:fmisa
    15 Comments
     
    LVL 5

    Expert Comment

    by:mrielf
    Hi!
    I think you shold not redirect back to url in your servlet, instead serve the url content through your servlet if user is authenticated. (or use a regular html page for it)

    Use Rewrite like this:

    RewriteEngine on

    ## If the requested url is your servlet, then do nothing
    RewriteRule ^/webapp/servlet/forceLoginDirect - [L]

    ## else do the redirection
    RewriteRule ^(.*)/download/(.*) http://host/webapp/servlet/forceLoginDirect?urlKey=%{REQUEST_URI}

    0
     
    LVL 5

    Expert Comment

    by:mrielf
    One more thing.

    If you want to authenticate at downloads only, yo can use download protector scripts for it with combination rewrite rules (onyl exclude the script from rewriting like the servlet)

    And always place the RewriteRule witch do the redirection at the end of rules

    0
     

    Author Comment

    by:fmisa
    I'll be a little red faced -- though happy to be on the right track finally -- if what you're saying works.....

    The content I need to serve is on the same web server (application server) as my servlet -- but I though in order to "serve" this content (which could be file like pdf, doc etc. not just html) my servlet would have to:
    * redirect() -> which get's me back to the endless URL redirect issue...
    * forward() -> which I cannot do beyond the servlet's "context" ??
                         (i.e. I can't forward to "http://..." or "../../webapp/" only to "/webapp/.../.."

    Am I missing something fundamental here ??

    Thanks for replying......

    Maybe I'm wrong ?
    But I think I'm offering a huge number of points for this ?

    Can you please a) supply source code snippet b) comment on other solutions if it turns out that mod_rewrite/servlet approach is not going to be able to work ?

    Here's the scenario.....
    1) User requests:
    http://someHost/headoffice/downloads/someFile.xls

    2) Apache mod_rewrite rules - redirect to:
    http://someHost/webapp/servlet/forceLoginDirect?
         urlKey=/headoffice/downloads/someFile.xls&
         httpHost=someHost

    3) My servlet - checks authentication - if OK - then executes the following:
        String redirectURI = request.getParameter("urlKey");
        String httpHost = request.getParameter("httpHost");    
        response.sendRedirect("http://"+httpHost+redirectURI);

    4) Problem is - on redirect %{REMMOTE_ADDR} IP is still that of original "client" -- not my web/ApplicationServer ?
       So the following mod_rewrite condition: RewriteCond %{REMMOTE_ADDR} !httpServerHost
       does NOT prevent the endless URL redirection ??
       Forward is not possible from servlet - I think - beyond the servlets own directory tree/context.....

    Hope I'm missing something obvious ??

    Thanks for working this question with me....

    0
     
    LVL 5

    Expert Comment

    by:mrielf
    After authentication check dont redirect to the original page. Redirect it to a dowload script instead.

    What kind of Web language you using?

    PHP is ok? (I can show you scrips for this in php)
    0
     
    LVL 5

    Expert Comment

    by:mrielf
    And what you want? The link is opened in the window or force downlad files?
    0
     

    Author Comment

    by:fmisa
    I'm using JSP for scripting.... would you have a JSP example ?
    0
     
    LVL 5

    Expert Comment

    by:mrielf
    My idea about to redirect to download script isn't good...
    You must integrate two script in one (to prevent security issues)

    Look at this component:

    http://www.javazoom.net/jzservlets/download4j/download4j.html#overview

    I think it will help you out...
    0
     

    Author Comment

    by:fmisa
    I will look at this product tonight.
    However, I was hoping to let:
       * Apache take care of serving the content.
       * Servlet take care of the authentication
       * and mod_rewrite to switch between the two.....

    Completely transparent to the end user.....

    If I can't perform this using just apache/module and servlet -- then I'm leaning away from using 3rd party products.  I really don't know how these unknown/untested components will perform in production/load ??

    I'm hoping someone here can answer my question definitively......

    1) Yes -- this is how mod_rewrite/servlet can do what you want....
    2) No -- for these reasons.... it's not possible -- but you could use this approach instead..... hopefully without having to resort to 3rd party products....

    I'll consider your thoughts on 2) -- but hope someone here can address 1) for me.....

    Talk Soon

    Thanks very much
    0
     
    LVL 5

    Accepted Solution

    by:
    Sorry I'm not good at JSP programing, but here is the idea:

    You must set these headers with response.setHeader:

    Cache-Control: private
    Pragma: public    
    Content-type: application/x-download
    Content-Disposition: attachment; filename="FileName"
    Accept-Ranges: bytes
    Content-Length: FileSize

    I found this script (rewriten by me litle). You can rewrite it to your needs:



    <?xml version="1.0"?>
    <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="1.2">

    <jsp:directive.page session="false" import="java.io.*" />
    <jsp:scriptlet>
       String p = request.getQueryString();
       boolean ok = true;
       ok = p!=null;
       if (ok) {
          response.setHeader("Content-type","application/x-download");
          response.setHeader("Content-disposition",
             "attachment; filename="+p);
          try {
             int l = (int) new File(p).length();
             response.setContentLength(l);
             byte[] b = new byte[l];
             FileInputStream f = new FileInputStream(p);
             f.read(b);
             ServletOutputStream o = response.getOutputStream();
             o.write(b,0,l);
             o.flush();
             o.close();
             f.close();
          } catch (Exception e) {
             ok = false;
          }
       }
       if (!ok) {
          response.sendError(HttpServletResponse.SC_BAD_REQUEST);
       }
     </jsp:scriptlet>
    </jsp:root>
    0
     

    Author Comment

    by:fmisa

    Not sure if this going to work - in a scalable manner ?

    >> FileInputStream f = new FileInputStream(p);

    "p" is the "filename"

    But all I've got is the requested URL.....
    Apache is already managing the alias mapping//translation to hard-drive for me;  I don't want to do this from my servlet ?

    RootDrive:\
                    HTTPSeverFolder\
                           htdocs\
                               downloads\
                                   MyFile.pdf
                    AppServerFolder\
                           App\
                                WEB-INF\
                                     classes\
                                                MyDownloadServlet.class

    1) How is my servlet going to "map" URL http://host/download/MyFile.pdf   ==>  drive:\\HTTPServerFolder\htdocs\downloads\MyFile.pdf   ??
         I could have many diffent alias and download directories -- I don't want to manage this meta-data in servlet..... which is why I wanted apache to do the work of download.
         I guess I could use somekind of url/folder naming convention -- but this whole approach is starting to feel like a real hack ? Don't you think.

    2) Can the servlet even see/access files outside the scope of it's "context" ..... WEB-INF ??
         I suspect - if I use absolute file path (not relative) - I should be able to open any file on the harddrive -- but then that brings me back to point 1) ??


    Am I missing something ?

    I had hoped that what I'm looking to do with mod_rewrite/AuthenticationServlet should be easy ??
    Surely someone out there has done something similar without have to resort to creating a sort of mini-web/content server in their servlet ??

    Any ideas out there ???
    0
     
    LVL 5

    Expert Comment

    by:mrielf
    Alternative solution is that not to use rewrite module, instead set apache authentication with alternative authentication module...

    Authentication with external CGI or PHP script
    http://mod-auth-script.sourceforge.net/

    External Authentication Module:
    http://unixpapa.com/mod_auth_external.html

    Apache authentication module using IBM DB2
    http://mod-auth-ibmdb2.sourceforge.net/

    0
     

    Author Comment

    by:fmisa
    Thanks for your patience .....

    I appreciate your help -- you've got me on the right track......

    Please give me another day or two to evaluate -- it's almose working right......
    I just want to make sure the code works right before I "accept"


    Thanks


    Frank
    0
     

    Author Comment

    by:fmisa
    Thanks  mrielf......

    I really appreciate the help.......
    I've accepted -- though I was worried about the overhead of having a servlet serve all the requested "static" content back instead of the HTTP server.
    I've tested -- and the extra overhead does not seem to be a big deal ?

    ** Though I have accepted -- please comment -- one last time on the following........

    Though Netscape is working fine -- MSIE is giving me very strange behaviour;  would you be kind enough to comment on the following behaviour:

    Everything works fine in the MSIE scenario -- my JSP page is executed -- and when I "print out" values of parameters only the "fileName" is correct.
    However, when I actually allow the following code to execute -- it seems the "fileName" is not being set correctly ??

    >> response.setHeader("Content-type","application/x-download");
    >> response.setHeader("content-disposition","attachment;filename=.....
    >> //....etc.etc.
    >> File aRequestedFile = ....
    >> //.... base my code on your example etc.etc.
    >> o.write(b,0,l);
    >> o.close();
    >> o.flush();

    Whenever the requested URL is https://.....   i.e. a long paramter value associated with the key:  ?krypto=kZtbzjcqp.....etc.  
    It seems the MSIE file download dialog pops-up -- prompting me to "SAVE"  or "OPEN"  
    BUT -- the fileName is NOT the fileName I set in my response header ??
    Instead -- it seems to include the a portion of the "krypto" parameter value ??

    Any idea what might be confusing MSIE ??
    Again -- Netscape seems to be working better.......

    Hope to hear from you one last time......

    Thanks for your help.....


    Frank



    0
     

    Author Comment

    by:fmisa
    Also....

    FYI

    * My research into apache modules:
        a) mod_auth_any
        b) mod_auth_external
        suggests I'd most likely get into scenarios where users would have to authenticate twice.

    * Servlet "Filters" I believe -- would give a better solution -- but don't think I can run "Filters" on my current version of WebSpherev.4.x  ??
    See:
    https://urlrewrite.dev.java.net/
    http://publib.boulder.ibm.com/infocenter/wasinfo/index.jsp?topic=/com.ibm.wasee.doc/info/ee/ae/tsec_servlet.html

    I'll look into "filters" more carefull later......


    Cheers
    0
     
    LVL 5

    Expert Comment

    by:mrielf
    Hi!

    This is a php example for this problem (i found it on the net):

        $user_agent = strtolower ($_SERVER["HTTP_USER_AGENT"]);
        if ((is_integer (strpos($user_agent, "msie"))) && (is_integer (strpos($user_agent, "win"))))
        {
          header( "Content-Disposition: filename=".basename($filename).";" );
        } else {
          header( "Content-Disposition: attachment; filename=".basename($filename).";" );
        }

    From this examle, it seems to me, if client is MSIE, then "attacment; " part must be excluded.

    (Sorry for php source. As I said, I'm not expert at jsp programing. Also sorry for my bad english)
    0

    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

    How your wiki can always stay up-to-date

    Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
    - Increase transparency
    - Onboard new hires faster
    - Access from mobile/offline

    [Part 4 of a 6 part series called SEO Basics: 5 SEO Secrets for Creating Content that Drives Traffic (http://www.experts-exchange.com/Web_Development/Internet_Marketing/Search_Engine_Optimization_SEO/A_8369-SEO-Basics-5-SEO-Secrets-for-Creating-Cont…
    [Part 5 of a 6 part series called SEO Basics: 5 SEO Secrets for Creating Content that Drives Traffic (http://www.experts-exchange.com/Web_Development/Internet_Marketing/Search_Engine_Optimization_SEO/A_8369-SEO-Basics-5-SEO-Secrets-for-Creating-Cont…
    This tutorial walks through the best practices in adding a local business to Google Maps including how to properly search for duplicates, marker placement, and inputing business details. Login to your Google Account, then search for "Google Mapmaker…
    The viewer will learn how to dynamically set the form action using jQuery.

    933 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    20 Experts available now in Live!

    Get 1:1 Help Now