I am working on a project using Netbeans with Glassfish 3.1 and am trying to implement LDAP authorization. To do so, I also have an LDAP-enabled Apache2 server using mod_jk. The gist is, when an user visits any page on the site in the /sng/ directory, the Apache server should ask for credentials and forward the user to the Glassfish server that is running that part of the site.
Apache is properly queueing for, and accepting, LDAP credentials and then forwarding the user to the appropriate area. But it seems that the REMOTE_USER variable is either not being set by Apache and/or not sent by mod_jk. Related configuration files and code snippets follow:
httpd.conf
<Location />
AuthBasicProvider ldap
AuthLDAPURL ldap://mainframe/ou=People,dc=dtch,dc=com?uid?sub
AuthzLDAPAuthoritative off
AuthType Basic
AuthName "LDAP"
require valid-user
Options Indexes FollowSymLinks MultiViews +Includes
</Location>
conf.d/jk
JKWorersFile /path/to/workers.properties
JkShmFile /path/to/mod_jk.shm
JkLogFile /path/to/mod_jk.log
JkLogLevel info
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories
workers.properties
worker.list=worker1
worker.worker1.port=8009
worker.worker1.host=127.0.0.1
worker.worker1.type=ajp13
sites-enabled/000-default
...
JkMount /*.jsp worker1
JkMount /sng/* worker1
web.xml
<filter>
<filter-name>RemoteUser</filter-name>
<filter-class>path.to.RemoteUser</filter-class>
</filter>
<filter-mapping>
<filter-name>RemoteUser</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
RemoteUser.java
//...
public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain )
throws IOException, ServletException
{
if( request instanceof HttpServletRequest )
{
HttpServletRequest httpServletRequest = ( HttpServletRequest )request;
String username = httpServletRequest.getHeader( "REMOTE_USER" );
if( username == null )
{
// enter here every time
}
// ...
}
//...
}
Finally I have registered a listener in the Glassfish control panel:
In short, I have no idea why null is being returned constantly and my searches on the internet have been of no help. Thanks in advance for any input you may provide.
note: httpServletRequest.getRemoteUser( ) provides the same null result.
I too had this problem. I found an answer by accident on another post. You have to update your server.xml in tomcat as follows:
<Connector protocol="AJP/1.3" port="..." ...
tomcatAuthentication="false" />
The tomcatAuthentication must be specified. Once I made the update, bounced tomcat, getRemoteUser() worked for me.
I was never able to retrieve a RemoteUser header, but I found a work-around in the form of the authorization header. Using getHeader( "authorization" ) returned to me a string in the form of:
Basic XXXX:YYYY
Where X is the username, and Y the password of the user accessing the page through Apache/mod_jk.
The portion of the string following 'Basic ' (X:Y) was Base64 encoded, so after decoding it with MiGBase64 I was finally provided with an username that I could use.
Related
I am replacing Siteminder with Apache Shiro in my web application. I noticed that shiro logs me in successfully and takes me to the home page. When i click on any other link on the home page, I am taken back to the login page. I login again and i am forwarded to the page i was looking to goto. How can i fix this?
Here is my shiro.ini
[main]
authc.loginUrl = /login.jsp
ssl.enabled=false
[users]
user=admin
[urls]
/css/** = anon
/images/** = anon
/js/** = anon
/login.jsp = authc
/logout = logout
/** = authc
A section from my web.xml
<listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>
<filter>
<filter-name>ShiroFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ShiroFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
Printing out currentUser.isAuthenticated() in my User Class displays 'true'.
Is there any other info i can provide?
I believe the problem is related to the fact that in the shiro.ini file you are not enforcing SSL:
ssl.enabled=false
However, in the weblogic.xml file you are enforcing SSL for cookies:
<session-param>
<param-name>CookieSecure</param-name>
<param-value>true</param-value>
</session-param>
So, my recommendation would be to change shiro.ini to:
ssl.enabled=true
And leave the original weblogic.xml file in place.
That way you will only accept users who authenticated over SSL (which is a good practice).
Please let me know the results.
Thanks
Fabio #fcerullo
Your configuration looks almost exactly like the Shiro sample web app (in fact, yours is even better by using authc.loginUrl instead of the deprecated global 'shiro.loginUrl' that the sample app uses). The sample app does not exhibit the behavior you're seeing.
This leads me to believe that something else (another filter?) is causing problems for you. Do you have a little sample app that you can make available (maybe on Github) that demonstrates the problem? I'd be happy to take a look if this can be recreated.
I figured out what was going on. My application was deployed on Weblogic and i had the following section inside weblogic.xml which was causing the issue. Removing it, fixed it. Any idea why this caused it?
<session-param>
<param-name>CookieSecure</param-name>
<param-value>true</param-value>
</session-param>
I have experienced the same behaviour,but I am using Wildfly 10.0.0 , and apache shiro v 1.3.2.
I foun the solution here in this Jboss Forum article.
Setting the cookie name from JSESSIONID to something else fixes the issue.
The solution provided here was to add the following in shiro.ini
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
cookie = org.apache.shiro.web.servlet.SimpleCookie
cookie.name = shiro.session.id
sessionManager.sessionIdCookie = $cookie
This worked for me.
I'm running a legacy CF Fusebox 5.5 app within Railo 4.0.2.002 Express with Jetty 8 on Mac OS X 10.8 with java 1.7.
I'm also using jetty urlrewrite http://tuckey.org/urlrewrite/ (if that's relevant)
Why is the FORM scope always blank upon form submissions? But if I use the URL scope it works fine.
The app has worked fine in all other versions of CF and should also work fine here.
UPDATE 1:
Also, when I do onRequestStart within Application.cfc and I dump the FORM scope it's empty there too.
Anyone have trouble with this? I don't think it's necessarily "fusebox" so I'm wondering if it's a Railo 4 compatibility issue?
UPDATE 2:
When the form posts to /admin/index.cfm?event=Main.Login
the form scope work fine. But when it posts to /admin/event/Main.Login the form scope is gone.
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite
PUBLIC "-//tuckey.org//DTD UrlRewrite 3.0//EN"
"http://tuckey.org/res/dtds/urlrewrite3.0.dtd">
<urlrewrite>
<rule>
<from>^/admin/event/(.*)</from>
<to last="false">/admin/index.cfm?event=$1</to>
</rule>
<rule>
<from>^/lms/event/(.*)</from>
<to last="false">/lms/index.cfm?event=$1</to>
</rule>
</urlrewrite>
UPDATE 3:
It should also be noted that Charles (proxy) is properly detecting the 'POST' Request contains the Email / Password and other form elements properly sent to the server.
The Jetty server is simply not seeing them or not properly forwarding them on to the Railo engine or something?
UPDATE 4:
Here is the tuckey configuration that they tell you to place in your web.xml. I actually placed this in the webdefault.xml in etc/ directory of Railo Express which I guess could just be Jetty files.
<filter>
<filter-name>UrlRewriteFilter</filter-name>
<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>UrlRewriteFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
I had a number of issues with Tuckey and ended up using Apache and modrewrite for features that Tuckey just didn't support. That being said Railo + Tomcat/Jetty is not ColdFusion with Jrun and the configuration was challenging to ensure that mod_rewrite had all the request information and even had the request at all. Even Adobe had to patch CF10 after release because they were missing original functionality from CF9-+JRUN connectors.
However, for your solution, you need to reach up and out. See the thread here.
https://groups.google.com/forum/#!msg/railo/uw-U9hCFu5k/bEmr_I2Kl8sJ
Other people have the same problem, and have worked around it by placing this in onRequestStart:
<cfscript>
if(gethTTPRequestData().method eq "POST") {
if(NOT structKeyExists(form,"fieldnames")) {
var paramMap = getPageContext().getRequest().getParameterMap();
var paramMapKeys = structKeyList(paramMap);
form.fieldnames = paramMapKeys;
for(x =1; x lte listLen(paramMapKeys); x++) {
param = listGetAt(paramMapKeys,x);
form[param] = paramMap[param][1];
}
}
}
</cfscript>
It's not clear if this is a bug in Jetty, Railo, or Tuckey.
I'm working on adding basic authentication to my RESTful web service (implemented using Spring MVC) with Spring Security having never really used it before. Right now I'm simply using an in-memory UserService with the intention of adding a repository-based one later.
<security:http>
<security:http-basic />
<security:intercept-url pattern="/**" access="ROLE_ADMIN" />
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="admin" password="admin"
authorities="ROLE_USER, ROLE_ADMIN" />
<security:user name="guest" password="guest"
authorities="ROLE_GUEST" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
This works fine, i.e. sending the following request grants me access to the desired resource (where the encoded string is admin:admin):
GET /user/v1/Tyler HTTP/1.1
Authorization: Basic YWRtaW46YWRtaW4=
And sending the following request gives me an Error 403 (where the encoded string is guest:guest):
GET /user/v1/Tyler HTTP/1.1
Authorization: Basic Z3Vlc3Q6Z3Vlc3Q=
However, sending a request where the provided username is not contained in the UserService does not result in an Error 403 as I expected (or at least desired) but instead continues prompting for a username and password. E.g. (where the encoded string is user:user):
GET /user/v1/Tyler HTTP/1.1
Authorization: Basic dXNlcjp1c2Vy
Is there additional configuration required to respond with an Error 403 when unrecognized user credentials are provided? How can I go about doing that?
Firstly,
403 Forbidden should be used when user is already authenticated but is not authorized to perform particular action. In your example guest is successfully authenticated but is not granted permission to see page because he is just a guest.
You should use 401 Unauthorized to indicate that your user was not authenticated successfully.
More on HTTP errors codes: http://en.wikipedia.org/wiki/HTTP_401#4xx_Client_Error
Secondly,
you can specify your custom behavior by extending BasicAuthenticationFilter.
There is protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse AuthenticationException failed) method that you can override and do whatever is adequate. In default implementation that method is empty.
Spring Security docs on injecting custom filter: CLICK
Edit:
What Spring Security does each time your authentication input is invalid:
public class BasicAuthenticationEntryPoint implements AuthenticationEntryPoint {
...
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
throws IOException, ServletException {
response.addHeader("WWW-Authenticate", "Basic realm=\"" + realmName + "\"");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
So, the default behavior is correct. User is sent 401 and is asked to provide valid login/credentials.
Before overriding, try to understand the default behavior. Source code: CLICK
You should try this in a client like wget or curl. You browser nags you several times for Basic redentials if your are rejected with 401. This is probably the case here.
I have pretty simple web-service, which runs on the Embedded Glassfish server:
#Stateless
#Path("/id")
#Produces(MediaType.TEXT_HTML)
public class SimpleFacadeBean {
#GET
public String sayHello(#Context HttpServletRequest request, #Context HttpServletResponse response) {
return "Hello world!";
}
}
And corresponding class, that set root-element for all web-service calls:
#ApplicationPath("root")
public class ApplicationConfig extends Application {
}
Everything works fine, but I want to protect this GET method through SSL.
I have read such manuals as: this, and this. I am not interested in configuring Glassfish part of SSL connection (I know how to do it), I just want not to see my GET method in localhost:8080/root/application.wadl link (this will mean that my web-service is connected to 8181 secure glassfish port, not to default unsecure 8080 port).
For this purpose I wrote web.xml descriptor and put it in webapp/WEB-INF directory. The most interesting part of it looks like:
<security-constraint>
<display-name>SecurityConstraint</display-name>
<web-resource-collection>
<web-resource-name>Secure Area</web-resource-name>
<url-pattern>/root/id</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
But after executing I saw (in application.wadl) again my web-service URL connected to unsecured port (8080 instead of 8181). I have tried a lot of other ways, trying to make my code work correctly. I was not successful at all.
I package this web-services into .war. After that this .war goes to .ear. Any ideas why I am not successful in NOT seeing my "secure" web-service in application.wadl?
I want to pass a security context to my rest service.
On server side I try to get this with:
public Response postObject(#Context SecurityContext security, JAXBElement<Object> object) {
System.out.println("Security Context: " + security.getUserPrincipal());
.....
But actually the Syso is null.
On Client side im just doing:
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
client.addFilter(new HTTPBasicAuthFilter("user", "password"));
So, do I have to change in addition something in my web.xml to get it working?
I hoped its working without setting up static users in the tomcat user xml. So I can compare the user/password from security context with my "persistent" user/password hashmap located server sided. But when it is not working without tomcat user xml, how can it be done to add dynamically user to that user xml? When I ve static users I cant register a new user. I dont want to use this attempt: http://objecthunter.congrace.de/tinybo/blog/articles/89 cuz I want just to work with a semi persistence like a HashMap of user/password.
Besides another question: Why does everybody refer to Apache HttpClient when it is about security in Jersey, when it is working like I wrote as well?
My attempt refers to this post:
Jersey Client API - authentication
You need to set up your application on the server so that it requires Basic authentication. I.e. include something like the following in the web.xml in your application war file - otherwise Tomcat does not perform the authentication and does not populate the security context.
<security-constraint>
<display-name>Authentication Constraint</display-name>
<web-resource-collection>
<web-resource-name>all</web-resource-name>
<description/>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<description>authentication required</description>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>realm_name</realm-name>
</login-config>