tomcat realm set user roles dynamically - java

I am using tomcat security for my application:
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
<!--This is only applicable for Tomcat 8.5 and higher version with SQL server authentication-->
<Realm className="org.apache.catalina.realm.JDBCRealm"
driverName="com.microsoft.sqlserver.jdbc.SQLServerDriver" connectionURL="jdbc:sqlserver://xxx.xx.xxx.xxx:1433;databaseName=xxxxx" connectionName="xxxx" connectionPassword="xxxx" roleNameCol="role_name" userCredCol="user_pass" userNameCol="user_name" userRoleTable="user_roles" userTable="users">
<CredentialHandler algorithm="MD5" className="org.apache.catalina.realm.MessageDigestCredentialHandler"/>
</Realm>
</Realm>
Now I want to be able to dynamically set new roles to the logged-in user from within the application whatever the authentication datasource may be. I need this to be deployed in an application and the client won't let us have the authentication database details and would prefer to themselves set the realm details. So it should work for all server/database types and hence be generic to the extent as possible.

Related

DataSourceRealm not working since changing from JDBCRealm in Tomcat

I am attempting to upgrade an existing web application to run on Tomcat 10.1 from Tomcat 9.0 where it works fine. My web application currently uses JDBCRealm but this appears to now be deprecated with Tomcat 10.1 and are now advised to use DataSourceRealm instead.
I have attempted to follow the instructions on the Apache website to use the DataSourceRealm instead and upgraded both my context.xml and server.xml however my authentication isn't now working.
Here is my context.xml file:
<Context path="/TASSU"> <Realm className="org.apache.catalina.realm.DataSourceRealm" connectionName="root" connectionPassword="sesame"
connectionURL="jdbc:mysql://localhost:3306/login_details" debug="99" driverName="com.mysql.jdbc.Driver"
roleNameCol="Rolename" userCredCol="Password" userNameCol="Username" userRoleTable="userrole" userTable="userpass"/>
And here is the realm information within my server.xml file:
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
<Realm className="org.apache.catalina.realm.DataSourceRealm" connectionName="root" connectionPassword="sesame"
connectionURL="jdbc:mysql://localhost:3306/login_details" debug="99" driverName="com.mysql.jdbc.Driver"
roleNameCol="Rolename" userCredCol="Password" userNameCol="Username" userRoleTable="userrole" userTable="userpass"/>
Here is the error that is being displayed in the logs:
25-Jan-2023 10:13:50.699 SEVERE [http-nio-8080-exec-23] org.apache.catalina.realm.DataSourceRealm.open Exception performing authentication
Can anyone see at first glance what the issue could be here? Have I set these two files up correctly?

Extend Tomcat manager app access through external file

We have access to the tomcat manager app restricted by authentication and IP address. See example config:
<Context docBase="${catalina.home}/server/webapps/manager"
privileged="true" antiResourceLocking="false">
<Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="{some-ips}"/>
<!-- Link to the user database we will get roles from -->
<ResourceLink name="users" global="UserDatabase"
type="org.apache.catalina.UserDatabase"/>
</Context>
Is there any way to reference an additional file on the local machine that determines additional IP addresses that are allowed to access the manager app?
Thanks.

Please check JNDI Realm Configuration

My Tomcat web application logs are telling me the user1 isn't in the specified mapped LDAP role/group coming from AD. I believe my issues lie with the JNDI Realm definition. Can someone review it please and see where I may be going wrong, I've included the DN information from AD as well:
My "user1" account DN is
DistinguishedName : CN=user1,OU=Users,OU=Lab,DC=example,DC=com
The role/group "Users" I have specified in the web.xml config is
DistinguishedName : CN=Users,CN=Builtin,DC=example,DC=com
My Realm configuration is
<Realm
className="org.apache.catalina.realm.JNDIRealm"
debug="99"
connectionURL="ldap://example.com:389"
authentication="simple"
referrals="follow"
connectionName="cn=administrator,cn=users,dc=example,dc=com"
connectionPassword="##########"
userSearch="(sAMAccountName={0})"
userBase="cn=users,dc=example,dc=com"
userSubtree="true"
userRoleName="memberOf"
roleSearch="(member={0})"
roleName="cn"
roleSubtree="true"
roleBase="cn=users,cn=builtin,dc=example,dc=com"/>
Fixed myself. This was the correct configuration.
<Realm
className="org.apache.catalina.realm.JNDIRealm"
debug="99"
connectionURL="ldap://example.com:3268"
authentication="simple"
referrals="follow"
connectionName="cn=administrator,cn=users,dc=example,dc=com"
connectionPassword="########"
userSearch="(sAMAccountName={0})"
userBase="dc=example,dc=com"
userSubtree="true"
userRoleName="memberOf"
roleName="cn"
roleSubtree="true"/>

Apache Tomcat Load Balancing Cluster

I am having 3 servers installed with Ubuntu and I want to configure Tomcat Load Balancing.
Server A = 10.0.0.1,
Server B = 10.0.0.2,
Server C = 10.0.0.3
I have pointed Domain to Server A which is having Apache and Mod_JK installed. while Server B and C is having Apache Tomcat 8. below is the Details of my workers.properties file
workers.apache_log=/var/log/apache2 worker.list=tomcatlb,status
worker.stat1.type=status
worker.tomcat1.type=ajp13 worker.tomcat1.host=10.0.0.2 #put your app
host here worker.tomcat1.port=8009 worker.tomcat2.type=ajp13
worker.tomcat2.host=10.0.0.3 worker.tomcat2.port=8009
worker.tomcat1.lbfactor=1 worker.tomcat2.lbfactor=1
worker.tomcatlb.type=lb
worker.tomcatlb.balance_workers=tomcat1,tomcat2
worker.list=jkstatus worker.jkstatus.type=status
I have also used jvmRounte name as tomcat1 and tomcat2 in server.xml of both the Apache Tomcat.
i have also added below lines in server.xml
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat2">
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
channelSendOptions="6">
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Membership className="org.apache.catalina.tribes.membership.McastService"
address="228.0.0.4"
port="45564" frequency="500"
dropTime="3000"/>
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
</Sender>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="auto" port="4001" autoBind="100"
selectorTimeout="5000" maxThreads="6"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interc eptor"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/>
</Channel>
context.xml is like below
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- The contents of this file will be loaded for each web application -->
<Context>
<!-- Default set of monitored resources. If one of these changes, the -->
<!-- web application will be reloaded. -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!--
<Manager pathname="" />
-->
<!-- Uncomment this to enable Comet connection tacking (provides events
on session expiration as well as webapp lifecycle) -->
<!--
<Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
-->
<Manager className="org.apache.catalina.ha.session.DeltaManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"/>
<Manager className="org.apache.catalina.ha.session.BackupManager" />
</Context>
apache configuration is having below lines
RewriteEngine on
RewriteRule ^/$ /test [PT,L]
JkMount /* tomcatlb
apache is redirecting the request to Tomcat via mod_jk and its working fine but when one tomcat goes down it should redirect the request to the other tomcat instead of that I have to do relogin as its not replicating the session.
I'm seeing that you're missing
stickysession=JSESSIONID|jsessionid lbmethod=byrequests nofailover=Off connectiontimeout=5 timeout=30
Just to be sure: These are actually separate lines:
worker.tomcat1.type=ajp13 worker.tomcat1.host=10.0.0.2
Besides: Is it intentional, that 10.0.0.1 is missing in your worker properties?

Tomcat 7 nesting CombinedRealm, LockoutRealm and DataSourceRealm

I'm trying to nest Realms as follows in Tomcat 7.0.32 (written here in pseudo-XML):
<CombinedRealm>
<LockoutRealm>
<DataSourceRealm/>
</LockoutRealm>
<UserDatabaseRealm/>
</CombinedRealm>
This doesn't seem to work - is it possible to nest Realms in Tomcat by more than two levels? I get a warning in the logs:
No rules found matching 'Server/Service/Engine/Realm/Realm/Realm'.
The idea behind is that the web service has some critical users that must not be locked out (e.g. as a DOS) and some normal users, which may have weaker passwords, where the lockoutRealm should be active. I'm sure other people have been in this situation.
If there is another way to achieve this (e.g. a whitelist for the LockoutRealm), please let me know.
Single sign on is also needed.
I guess extending the existing LockoutRealm code with a list of accounts never to lock out would be an option, but I'm not so keen on writing my own Realm, I would rather not add custom code on that level to Tomcat, as this will complicate setup for others and with every Tomcat update it might break etc.
Thanks for any help!
Here is the relevant part of server.xml of my test config:
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.CombinedRealm">
<!-- Lockout realm for the DB users -->
<Realm className="org.apache.catalina.realm.LockOutRealm">
<!-- PRIMARY: DataSourceRealm with user DB -->
<Realm className="org.apache.catalina.realm.DataSourceRealm"
dataSourceName="jdbc/authority"
userTable="user" userNameCol="username"
userCredCol="password" digest="SHA"
userRoleTable="user_role" roleNameCol="rolename" />
</Realm>
<!-- FALLBACK:
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>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<!-- SingleSignOn valve, share authentication between web applications
Documentation at: /docs/config/valve.html -->
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
<!-- Access log processes all example.
Documentation at: /docs/config/valve.html
Note: The pattern used is equivalent to using pattern="common" -->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log." suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
</Engine>
Apache commons-digester is used to parse the configuration files, so I suspect this particular use case simply wasn't expected.
Tomcat's org.apache.catalina.startup.RealmRuleSet.addRuleInstances seems rigged to only go 2-levels deep for Realm configuration. Seems simple enough to add another layer in there.
I'd have to look at how the digester can be configured to see if arbitrary levels could be supported, or if some subset would have to be manually configured.
Feel free to head over to the Tomcat users' list to request such a change.
The new answer is now:
Update to Tomcat 7.0.33 or later. Then it works perfectly.
Christopher Schultz was so friendly to forward my question here to the Tomcat user list. The great Tomcat developers have immediately addressed the issue and put this in the next release. Thanks a lot!
So you can now use a construction like the one in the question or like this with different order / "priorities":
...
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.CombinedRealm">
<!-- PRIMARY: tomcat-users.xml with critical system users
that should always work, DB independent and without lockout
NOTE: If the wrong password is given, the secondary path with
lockout is still attempted, so that a lockout on that path
will still occur and be logged. Still the primary path is not
locked for access by that happening. -->
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
<!-- SECONDARY: DataSourceRealm with DB with lockout functionality -->
<!-- (three level nesting of realms requires Tomcat >= 7.0.33) -->
<Realm className="org.apache.catalina.realm.LockOutRealm"
failureCount="5" lockOutTime="60" > <!-- note that when an account is locked correct password
login is no longer possible (would otherwise defeat purpose of lockout),
but also lockoutTime is still reset in each correct attempt -->
<Realm className="org.apache.catalina.realm.DataSourceRealm"
dataSourceName="jdbc/authority"
userTable="user" userNameCol="username"
userCredCol="password" digest="SHA"
userRoleTable="user_role" roleNameCol="rolename" />
</Realm>
</Realm>
<Host >
...
</Host>
</Engine>
...
Of course you may also use other Realms and other combinations.
Note that one thing can be misleading in the logs: In this construction, if a wrong password is given for one of the critical users stored in the primary realm, the primary realm denies access, then the secondary realm via the lockout realm is tried and also denies access eventually locking out the username. This is logged by the lockout realm as a warning "An attempt was made to authenticate the locked user ...". Still with correct password, access keeps working via the primary realm, as it does not go via the lockout realm. I.e. all works as intended, just the log message could lead to confusion (of course this is impossible to avoid).

Categories