I'm implementing a REST-API in Java, using Jersey3 and a Tomcat10. In order to provide/restrict access to some endpoints for specific roles, I would like to use a DataSourceRealm.
The configuration in my context.xml looks like this:
<Resource type="javax.sql.DataSource"
name="jdbc/myDB"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
driverClassName="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:#//localhost:1521/orcl"
username="xx"
password="xx"/>
<Realm className="org.apache.catalina.realm.DataSourceRealm" debug="99"
dataSourceName="jdbc/myDB" localDataSource="true"
userTable="USERS" userNameCol="USERNAME" userCredCol="PASSWORD"
userRoleTable="USER_ROLES" roleNameCol="ROLENAME"/>
The dataSource is also defined in my context.xml and can be accessed with JNDI.
In my web.xml I defined the following security constraint:
<security-constraint>
<web-resource-collection>
<web-resource-name>Some name</web-resource-name>
<url-pattern>/api/data</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>Administrator</role-name>
</auth-constraint>
</security-constraint>
So every GET request with the pattern /api/data requires the role Administrator
Table USER_ROLES has one entry with USERNAME=admin and ROLENAME=Administrator.
Also, I've added these lines:
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
<security-role>
<role-name>Administrator</role-name>
</security-role>
For doing the obvious.
A corresponding endpoint is defined like this:
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/data")
#RolesAllowed({"Administrator"})
public Response getData(...)
Added these lines to my log-config:
org.apache.catalina.realm.level = ALL
org.apache.catalina.realm.useParentHandlers = true
org.apache.catalina.authenticator.level = ALL
org.apache.catalina.authenticator.useParentHandlers = true
Calling http://localhost:8080/myapp/api/data in a GET with Authentication header Basic YWRtaW46YWRtaW4= --> admin:admin
Restricting access so far works and my DataSourceRealm seems to be taken into account. Although there are no logs from the when someone is authenticating.
What would I need to add, in order so see logs from the DataSourceRealm?
Any help/input would be much appreciated.
Related
I have three jsf web application deployed on tomcat web server with SSL/TLS enabled. Now I want to build some kind of SSO authentication with particular roles. In tomcat conf/server.xml there is line:
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
so I got idea that tomcat maybe have his own SSO implementation. Does anyone know where to find more information about this or some code examples?
Thanks in advance
After many hours of research I found solution, so I will post it here in case someone need SSO authentication in tomcat.
First of all open conf/server.xml file in tomcat installation directory and add following line:
<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
</Host>
By doing this, you have opened SSO valve. Next, you need to set up roles in tomcat. That is done by editing conf/tomcat-users.xml. Scroll to the bottom and add roles, something like this:
<role rolename="CUSTOMER"/>
<role rolename="ADMIN"/>
Now, if you want plain text authentication you can add users also by adding :
<user username="admin" password="admin" roles="ADMIN"/>
<user username="customer" password="customer" roles="CUSTOMER"/>
or, if you have database you can set up connection with database server in conf/server.xml, I'm using MySQL:
<Realm className="org.apache.catalina.realm.JDBCRealm"
driverName="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/databaseName?user=serverUsername&password=serverPassword"
userTable="usersTable" userNameCol="usernameColumnName" userCredCol="passwordColumnName"
userRoleTable="roleTable" roleNameCol="roleColumnName"/>
Note: You need to provide connection driver in tomcat lib directory.
More info on: https://tomcat.apache.org/tomcat-7.0-doc/realm-howto.html#JDBCRealm
Finally in your web app or apps, find web.xml and add security constrains:
<security-constraint>
<web-resource-collection>
<web-resource-name>Protected Context</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
<auth-constraint>
<role-name>ADMIN</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>this is ignored currently</realm-name>
</login-config>
<security-role>
<role-name>ADMIN</role-name>
</security-role>
Note: if you have custom Login page you can edit <login-config> tag and change to following:
<login-config>
<auth-method>FORM</auth-method>
<realm-name>file</realm-name>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/error.jsp</form-error-page>
</form-login-config>
</login-config>
Cheers.
Apache 9 Single Sign On Valve documentation is here: https://tomcat.apache.org/tomcat-9.0-doc/config/valve.html.
Since you mentioned JSF (I'm not sure if you are using PrimeFaces & OmniFaces), maybe you are struggling also with log out/session time out. Specially if end user has open multiple windows/tabs and multiple applications (you mentioned you have three JSF apps), then
OmniFaces FacesExceptionFilter and
OmniFaces FullAjaxExceptionHandler
would be helpful for you. I can also recommend the best JSF book I've ever read
The Definitive Guide to JSF in Java EE 8 written by BalusC (JSF expert, author of OmniFaces, etc.).
I want to create a simple JSP/Servlet login page that authenticate using websphere ldap repository.
All examples I've found looks very complex, with hundreds of lines of code just to authenticate.
Is this really so complex?
Does anyone have a simple example or article that explains how to authenticate a user/pass against a ldap repository already configured as websphere federated repository?
I really appreciate any help.
Thanks
This is quit simple in reality. You need following pieces:
1) Login page with form that points to j_security_check
See this page for details Customizing web application login
Very simplified example is like this:
<form method="POST" action="j_security_check">
<input type="text" name="j_username">
<input type="text" name="j_password" autocomplete="off">
<\form>
2) Security configured in web.xml
Something like this:
<login-config>
<auth-method>FORM</auth-method>
<realm-name>Example Form-Based Authentication</realm-name>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/login.jsp</form-error-page>
</form-login-config>
</login-config>
plus security constraint:
<security-constraint>
<display-name>allResources</display-name>
<web-resource-collection>
<web-resource-name>allResources</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>users</role-name>
</auth-constraint>
</security-constraint>
3) Application security enabled on the application server and user registry configured.
That's it.
I have set the realm setting in server.xml host section to something like this:
<Realm className="org.apache.catalina.realm.JDBCRealm" driverName="org.gjt.mm.mysql.Driver"
connectionURL="jdbc:mysql://localhost:3306/test" connectionName="test" connectionPassword="test"
userTable="users" userNameCol="user_name" userCredCol="user_pass" userRoleTable="user_roles"
roleNameCol="user_role" />
Also in web.xml:
<security-role>
<role-name>ADMIN</role-name>
</security-role>
<security-constraint>
<web-resource-collection>
<web-resource-name>critical</web-resource-name>
<url-pattern>/admin/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>ADMIN</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/error.jsp</form-error-page>
</form-login-config>
</login-config>
And I have the databased set up. However when login.jsp is envoked, even I entered the right password I was redirected to error.jsp
I want to know if there is a way to find what's wrong during the process. Can I do it in Eclipse or any other hints that may solve the problem?
To get the debug information from the Realm authentication steps, follow this procedure.
When you define your Realm in the server.xml, add debug="9" to the definition (you can of course use a lower number for less detail).
<Realm className="org.apache.catalina.realm.JDBCRealm" driverName="org.gjt.mm.mysql.Driver"
connectionURL="jdbc:mysql://localhost:3306/test" connectionName="test" connectionPassword="test"
userTable="users" userNameCol="user_name" userCredCol="user_pass" userRoleTable="user_roles"
roleNameCol="user_role" debug="9" />
You also need to add this to your logging.properties file:
org.apache.catalina.realm.level = ALL
org.apache.catalina.realm.useParentHandlers = true
org.apache.catalina.authenticator.level = ALL
org.apache.catalina.authenticator.useParentHandlers = true
You may also need to add this, to prevent bufferring of the logs. If you do, remember to remove it after you've finished debugging.
1catalina.org.apache.juli.FileHandler.bufferSize = -1
Now, the debug logs for the realms should end up in the catalina.out file.
For others finding this issue, I found the following worked for Tomcat 8.5.40:
java.util.logging.ConsoleHandler.level = ALL
org.apache.catalina.level = FINEST
org.apache.catalina.realm.JNDIRealm.level = FINEST
org.apache.catalina.realm.JNDIRealm.useParentHandlers = true
The key fact appears to be that your logging travels through several layers of definitions and will be trimmed by the first one that has a lower level so you need to make sure that each bit it passes through is FINEST or ALL.
Hopefully this will save someone some time ;)
Ian.
I am trying to put user access level in My Java Web Application.But even I enter the correct username and password which I have declare in the tomcat-user.xml file It is not working. It gong to loginerror page. Basic Authentication Method also Not Accepting Correct Username and password.
This tomcat-users.xml
<tomcat-users>
<!--
NOTE: By default, no user is included in the "manager-gui" role required
to operate the "/manager/html" web application. If you wish to use this app,
you must define such a user - the username and password are arbitrary.
-->
<!--
NOTE: The sample user and role entries below are wrapped in a comment
and thus are ignored when reading this file. Do not forget to remove
<!.. ..> that surrounds them.
-->
<!--
<role rolename="tomcat"/>
<role rolename="role1"/>
<user username="tomcat" password="tomcat" roles="tomcat"/>
<user username="both" password="tomcat" roles="tomcat,role1"/>
<user username="role1" password="tomcat" roles="role1"/>
-->
<role rolename=”Admin”/>
<role rolename=”Member”/>
<role rolename=”Doctor”/>
<role rolename=”Guest”/>
<user username=”sirojan” password=”sirojan” roles=”Admin” />
<user username=”ram” password=”ram123” roles=”Member” />
<user username=”vithu” password=”newbie” roles=”Guest” />
</tomcat-users>
This is a part of server.xml file
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.MemoryRealm" />
<!-- This Realm uses the UserDatabase configured in the global JNDI
resources under the key "UserDatabase". Any edits
that are performed against this UserDatabase are immediately
available for use by the Realm. -->
<!-- <Realm className="org.apache.catalina.realm.MemoryRealm" /> -->
<!-- This Realm uses the UserDatabase configured in the global JNDI
resources under the key "UserDatabase". Any edits
that are performed against this UserDatabase are immediately
available for use by the Realm. -->
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/><!--
--> </Realm>
This is My a part of web.xml file
<security-role>
<role-name>Admin</role-name>
</security-role>
<security-role>
<role-name>Member</role-name>
</security-role>
<security-role>
<role-name>Guest</role-name>
</security-role>
<security-role>
<role-name>Doctor</role-name>
</security-role>
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login2.jsp</form-login-page>
<form-error-page>/loginerror.jsp</form-error-page>
</form-login-config>
</login-config>
<security-constraint>
<web-resource-collection>
<web-resource-name>AdminTasks</web-resource-name>
<url-pattern>/Department.jsp</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>Admin</role-name>
<role-name>Member</role-name>
</auth-constraint>
</security-constraint>
<error-page>
<error-code>404</error-code>
<location>/notFoundError.jsp</location>
</error-page>
</web-app>
Did I anything wrong??. If you need further pl comment it. Can you please give the solutions for that??
first check whether the existing roles are working for you or not .
for that u need to uncomment the roles in tomcat-users.xml
if they are working ,and u r able to login in tomcat console, then problem is ur syntax ,
if they are not working then u need to go with the error page documentation and check what u r doing is correct or not because this is kind of easy and works every time for me .
I have the following Jetty setup:
<New class="org.eclipse.jetty.plus.jaas.JAASLoginService">
<Set name="Name">FOO JAAS Realm</Set>
<Set name="LoginModuleName">foo</Set>
<Set name="roleClassNames">
<Array type="java.lang.String">
<Item>foo.jaas.principal.UserPrincipal</Item>
<Item>foo.jaas.principal.RolePrincipal</Item>
<Item>org.eclipse.jetty.plus.jaas.JAASRole</Item>
</Array>
</Set>
</New>
I am using an Embedded Jetty 7.6.1.v20120215 via the Maven Jetty Plugin.
When I try to login via the form that I have, the logins fields are properly sent to /j_security_check. I have written my own LoginModule which is invoked and validates the users properly. I can see their principals are properly fetched from the database.
Instead of being shown the secured page, Jetty shows me:
HTTP ERROR 403
Problem accessing /foo/auth.html. Reason:
!role
I am not quite sure what it really means by that.
I have the following in my web.xml:
<security-constraint>
<web-resource-collection>
<web-resource-name>ADMINISTRATOR</web-resource-name>
<url-pattern>/auth.html</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>ADMINISTRATOR</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>foo</realm-name>
<form-login-config>
<form-login-page>/login.html</form-login-page>
<form-error-page>/authfail.html</form-error-page>
</form-login-config>
</login-config>
<security-role>
<role-name>ADMINISTRATOR</role-name>
</security-role>
<security-role>
<role-name>USER</role-name>
</security-role>
I am logging in as the administrator.
Any help on the cryptic JAAS message displayed by Jetty would be very much appreciated.
I had the same error and above code was already there....
but after reading: http://wiki.eclipse.org/Jetty/Tutorial/JAAS
I had to also update web-jetty.xml and add
<Set name="roleClassNames">
<Array type="java.lang.String">
<Item>login.RolePrincipal</Item>
</Array>
</Set>
in this section:
<New class="org.eclipse.jetty.plus.jaas.JAASLoginService">
because I used a custom made principal for roles "login.RolePrincipal" (actually I inherited the code and was moving the app from tomcat to jetty :) )
The user that is logging in does not have the role ADMINISTRATOR that you enforce on /auth.html.
During the commit phase,your JAAS Login module is expected to add the user roles to the Subject Principals. The roles are held in a class extending Principal which you indicate to Jetty in the jetty.xml file.
You login module should have something like this in commit()
Set<Principal> subjectPrincipals = subject.getPrincipals();
//add the roles
for (String role : userRolesList) {
subjectPrincipals.add(new RolePrincipal(role));
}
RolePrincipalis your role class