Continuing the series of hardening embedded Tomcat in Java to meet Nessus security scans, I am back with an example of adding a Content Security Policy to your app. There are some ways in a more standard Tomcat server to provide CSP policies, but with an embedded server that can be more difficult.
I have used an embedded Tomcat server for years to build applications. The following example is using Tomcat 10, but the principle is the same or Tomcat 9. The main difference as a Tomcat 9 to 10 transition is moving from the javax namespace to jakarta. With more and more libraries, such as Jooq, moving to more modern Java versions; as well as, some of the new Java versions offering good performance improvements out of the box, it may be time for everyone to move to the Jakarta namespace. (Even if that means leaving some libraries such as Google OAuth behind)
In my recent example project going over how to use Pac4J for Oauth with Tomcat 10, I have added an example here of what the FilterBase class would look like. You then need to initialize the filter where you are starting the Tomcat thread. That will add the needed header to all the web requests your application processes.
(I will ramble for a bit, if you just want the guide jump below) I want to start a series more around programing than the other articles I have put up here. I know everyone here knows me as the good-looking hardware hacking guy, but most of my time at work is spent on programming and systems automation. I haven’t used the programming tag on this blog in a while, and I want to start this new series beginning with discussing upgrading to Tomcat 10.
I have for years been using an embedded Tomcat + Servlet backend, with a jQuery frontend for different small webapps I have made. I know for anyone who learned webdev in the recent past that sounds very old. I am using more and more Dropwizard and React these days, but that does leave my legacy projects on this old framework. While not the newest or flashiest thing, it does perform well with some systems handling hundreds to thousands of calls a second. (My hope is to get approval and open source some of them soon.) With the changes in the Java universe, (after Oracle bought Sun and decided to ruin everyone’s fun and causing splintering) I had to start moving from the traditional JavaX servlet namespace that Tomcat 9 and before used to Tomcat 10s Jakarta namespace. Migrating the servlets themselves was not so bad. The first big issue arose around Google’s OAuth library. I have used this library for a long time. It provides the easy-ish ability to connect to any OAuth server you want (I have specific ones at work I use) for authentication. Recently Google, doing what they do, marked this library as Maintenance Mode Only, stating they would only do emergency security fixes, but overall, its abandoned. Not what you want to hear from your authentication library. They also are not planning to move it over the Jakarta namespace making me stuck on Tomcat 9 for as long as it has support. This should be a long-time sine many big companies and projects are right where I was, and the plan is for 9 and 10 to develop together for a long time. This does mean that I cannot use the newer features of Java though. From this I knew I had to start looking at other options.
Every time I have to work on auth systems, it is maze, and once I get it working, I want it to stay working for a while, where I hopefully don’t have to touch it. There are not a ton of OAuth libraries for Java backend systems, and I wanted one that I knew had community support and would last for a while. That brought me to the popular PAC4J project. A lot of the guides I found for using this were around using JavaX and/or using PAC4J to integrate with Google Auth, or Facebook Auth, or other auth systems. I want to be able to use the systems at work, or a more generic provider such as Keycloak. I spent a good amount of time bringing different bits of information together to get a fully working PAC4J 5.7 + Tomcat 10 + Servlets setup working. I posted it on Github, and below has a guide on how to configure Keycloak in Docker to demonstrate this. This took a fair amount of time to put together, I hope it helps you out there, if it does, please give the post a like or star the repo, it pushes me to keep doing these tutorials.
Keycloak Setup
To start at the beginning, Keycloak is a webserver that works as an Identity Provider (IDP). It has its own database for users and groups, or can link into many other systems such as Google, Facebook, and many more. When hooking up to it, you can decide to use SAML or OpenID. I tend to use OAuth which is a subset of the OpenID standard (I think thats the order). This guide will use Keycloak as our IDP, then connect to that with RAC4J. I do believe PAC4J has a more native and easier to use Keycloak integration, but where is the fun in that.
Keycloak out of the box has a Docker image for development. You optionally can attach persistent storage to make users and groups stay after you delete and rebuild the container. Using this container with local storage is not a good setup this way for production, you should use a database like Postgres to back the container instead. But for our home testing this setup is fine and will work well. I use persistent storage so I can have a local Keycloak that can be updated without recreating everything. More information about the Keycloak docker container can be found here.
Setting up Keycloak with persistent storage
docker volume create keycloak
# We need to set the keycloak user to be the owner of that folder
docker run --rm --entrypoint chown -v keycloak:/keycloak alpine -R 1000:0 /keycloak
docker run -p 8081:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -v keycloak:/opt/keycloak/data/h2 quay.io/keycloak/keycloak:20.0.2 start-dev --http-relative-path /auth
Keycloak can use OpenID as its connector which is more of a superset of OAuth itself. For this guide I want to go over using OAuth; so we will tweak some of the Keycloak configs to work how we want, as a generic OAuth provider.
Login with the username and password of “admin” that we set in creating the container
Click in the top left dropdown where it says “master” and create a new realm, we will call it “example“
Now that we are in your new realm, go to “Users” on the left
Create a new user, lets name this new user “Jon” (or whatever your heart desires)
Once created, click the “Credentials” tab, and set a password, I disable “temporary password” because this is not a production auth system
Click “Client Scopes” in the top left
“Create client scope“
Name “openid”
Type “Default“
Save
“Mappers” tab
“Add predefined mapper“
I did “full name”, “email”, “username”, “groups”
Note: I found the add screen here buggy, if you page to the next list of mappers, saving doesn’t work, so do one page at a time
Click “Clients” in the top left
“Create client“
Client-id “example-client”, I like to enable “Always display in console”, “Next”
Enable “Client Authentication”, then save.
“Client Authentication” enables “confidential access type”, this is the classic OAuth where you need a client secret to access the server
Go up to “Client scopes” and add the “openid” scope as a “Default” type
Note: I have found with PAC4J + Keycloak specifically, if you do not add the openid type, then you will get through auth but when PAC4J goes to get user information you will get an error of WARN org.keycloak.events type=USER_INFO_REQUEST_ERROR, realmId=59d04435-daf4-4ca7-8623-195769911c0e, clientId=null, userId=null, ipAddress=172.17.0.1, error=access_denied, auth_method=validate_access_token. You may also see WARN org.keycloak.services KC-SERVICES0091: Request is missing scope 'openid' so it's not treated as OIDC, but just pure OAuth2 request. If your client is not requesting the openid scope.
This can present itself to your client as a 401 or 403 error. As here and here, this helped me.
Go to the “Credentials” tab, view the “Client secret” and save that for later
Recently I updated my Windows sudo program and added a command for Super Conduit, this is what I call some tweaks that you can make to a Windows Vista+ system. This allows someone to copy sudo.exe to a systems, system32 folder; then after running “sudo cmd” you can run “sudo /write” so add ls, ifconfig, and superc as a option in the command line.
Superc has options of enable, disable, and show. Making it easy to run. 🙂
Recently I have been working on a project that involves extracting a bunch of files from zips. The problem I faced was all the shortcuts within the zips were hard coded to locations, making it impossible for me to move the extracted zip data to wherever I may want. I wanted a native library that could read and modify Windows Shortcuts so I could drop my zip data anywhere; my project is in Java, and its instant cross compatibility was needed. I know all my clients have Java installed, so that made its dependency not a issue. After looking around on the internet and finding several options, including the popular https://github.com/jimmc/jshortcut. Now the downside the this popular jShortcut library is you need a DLL, why you need a DLL to write a binary file, I am not sure. More specifically, you need a DLL for your PCs instruction set, ick! After searching the far reaches of github, and getting to the end of my rope I found https://github.com/kactech/jshortcut, written 5 years ago, and not really popular on github I thought I would give it a try. IT’S AMAZING! With no dependencies, and just a single include, you can write, modify, and create new Windows Shortcuts! There is example code included, and it couldn’t be easier to use. I just wanted to make sure anyone who has had the same problem knows about this great library.
If you have been writing web apps for a while, or other apps you more than likely have used SQL. SQL allows you to query a database and interact with your applications data. Instead of trying to find a users profile, what if we wanted to find out what a user was printing on their local machine? If there was an easy interface for that, it could make programming for a platform like Windows a lot easier. Well Microsoft years ago added this ability to Windows; the technology is called WQL. This was added with the other components of WMI (Windows Management Instrumentation) at Windows ME. For Windows 9x and NT you can download the WMI core. This article will be a brief over view of what it can do and how you can play around with it.
First like when we looked at LDAP, we want a tool that will let us quickly play around with what is available, and then code that into our application. The tool I use is WMI Explorer, http://www.ks-soft.net/hostmon.eng/wmi/, it provides a easy interface to look at all the data available. With the WMI core it works with everything back to Windows 95! You can download and run the program for free, no installation required. Once open, there is a upper portion of the window that lists all the spaces you can access, these would be the ‘tables’ in SQL. Depending on your version of Windows, there will be separate options available. I have used this interface before for network cards (6to4 Cleaner) and printers.
WMI Explorer
For this example I will go over to the Win32 framework and access the Win32_Printer ‘table’. I get a list of printers the machine has installed, as well as attributes to each of these printers. Any administrator, or any program attempting to manager printers (I say attempting because printers can he a horrible experience) information – like what port the printer is using – is here, in addition what type of connection this machine has to the printer. At the bottom of the Window there is a Query that is building as you select different fields. This query can be moved into a application later to get the same data in code. WMI Explorer also allows for a user to write Queries directly without this interface; that is the second tab at the top of the window.
One downside I have found in using WMI is the setup process time, in C#/.NET using WMI is easy, but it takes time to start accepting queries. About a year or two ago I was working on querying network card information on Windows Vista. The first call could take a few seconds to respond, after that first call it would speed up, this is just something that has to be accounted for in the applications design. I found running WQL queries in a separate process, and starting them as soon as possible would allow the process to finish before the user needed the data.
I just wanted to get everyone started looking at what is available, in a later article I will go into more depth about programming with this and how you can interact with this data in a C#/.NET program.
Last time I spoke of how to setup ldap with PHP and briefly touched on using the “ldapsearch” command. I would like to go more in-depth on “ldapsearch”, and show you how you can use it to craft searches for your PHP application. Specifically for RPI, if the user has a RCS account, they can ssh into “rcs-ibm.rpi.edu” and run the following commands. (RCS-IBM puts you on either clark.server.rpi.edu or lewis.server.rpi.edu, these two have the commands you need on them and run AIX) To briefly review the command:
First we add the command, then enter the host you are searching, tell the server to try simple anonymous authentication. Next give the server a base to start the search (I am using RPI specific domain components), finally we have to give the heart of our search. I am looking for any Unique ID (username) that starts with “berk”, and ends with anything “*”.
The main part of the search we will be editing is the ending. Here we specify a filter to find the information we are attempting to access. Each LDAP server has different attributes it can give about each object. For example, the ldap.rpi.edu server gives out “givenName, objectClass, cn(full concatenated name, or common name), sn (surname), loginShell,” and many others; while at the same time “ldap1.server.rpi.edu” returns a much different lists of results.
Finding Which Attributes Will be Returned
The best way to find which fields are available is by doing a search without a filter. Just running the search below will return an unfiltered list of everything in the directory, up till you hit the individual servers limit. I am purposefully not publishing results from these searches for privacy reasons; here is some results for me with some data omitted.
# berkod2, accounts, rpi, edu
dn: uid=berkod2,ou=accounts,dc=rpi,dc=edu
sn: Berkowitz
cn: Berkowitz, Daniel
objectClass: top
objectClass: posixAccount
objectClass: inetOrgPerson
objectClass: eduPerson
objectClass: rpiDirent
objectClass: mailRecipient
objectClass: organizationalPerson
objectClass: person
uid: berkod2
loginShell: /bin/bash
uidNumber: #####
mailAlternateAddress: berkod2@rpi.edu
givenName: Daniel
gecos: Daniel Berkowitz
rpiclusterhomedir: /home/berkod2
description: PRIMARY-STU
homeDirectory: /home/06/berkod2
gidNumber: ###
Now that we have an idea about the data structure and what this server has on it we can reverse the lookup and tweak it. I know ‘uid’ will be the username, and I can get the users name from that! So using CAS I can log a user in and get their username, then I can lookup there LDAP information. (EXAMPLE 1) If a user enters a name, then a user can search for their UID doing the reverse. (EXAMPLE 2) The wild card can also be used if the full name is not known. (EXAMPLE 3) Last we can use multiple fields, combining these ideas to narrow down the result. (Example 4)
After writing about how to use CAS with PHP, I thought I would write a post about how to use LDAP(Lightweight Directory Access Protocol) at RPI but these methods can be used anywhere. LDAP is a protocol to query user databases, this is a protocol that can be sed along with Active Directory, or another directory system for computers and user accounts. This protocol is widely used to allow different applications to interact with your user database. Here I will be showing how to implement search with LDAP to a web application. This guide will be using LDAP with PHP, this requires the LDAP module to be enabled within PHP; that will be the purpose of this article, then the next one will discuss how to actually query LDAP.
LDAP Linux (Debian/Ubuntu) Install
Linux is easy to get LDAP working with PHP, as long as you have a standard installation of Apache, with PHP 5 working.
Install the LDAP module onto the machine, using either aptitude or apt-get
“sudo aptitude install php5-ldap”
OR “sudo apt-get install php5-ldap”
PHP should now be able to use LDAP, if it is not working yet, you will need to restart Apache.
“sudo service apache2 restart”
LDAP Windows (XAMPP) Install
Xampp for Windows comes with LDAP, but there is a bug in their implementation and a file needs to be copied before LDAP will work. I am going to use “C:\xampp”, the default directory for Xampp in this example.
Go into the PHP folder, C:\xampp\php\
Edit the file “php.ini” with any text editor
Find the line “;extension=php_ldap.dll”, and remove the semi-colon. “extension=php_ldap.dll”
Now if you were to reboot Apache it should be working, but its not! Why not? There is a missing DLL. You need to
copy libsasl.dll from c:\xampp\php\libsasl.dll to C:\xampp\apache\bin\.
Now restart Apache
LDAP Search
Now that PHP can search LDAP we are going to want to start creating queries in PHP; but it is much easier to tweak the search in the command line, and then put that query into PHP. The following are steps that can be taken on a Linux computer (again Ubuntu/Debian) to install and use a ldap command line search.
First we need to install the OpenLDAP utilities that will give us the “ldapsearch” command
“sudo aptitude install openldap-utils”
OR “sudo apt-get install openldap-utils”
Now we are making our query
First we add the command, then enter the host you are searching, tell the server to try simple anonymous authentication. Next give the server a base to start the search (I am using RPI specific domain components), finally we have to give the heart of our search. I am looking for any Unique ID (username) that starts with “berk”, and ends with anything “*”.
Now this gives one result, and this can be used to see what data will be returned from this server. You can also try “ldap1.server.rpi.edu” this returns a entirely different list of variables, and sometimes more users.
Troubleshooting: For those of you here at RPI trying to follow this guide specifically, if you do not get any results or a error connecting, RPI firewalls the LDAP servers heavily. I have found a lot of the time I have to be in the VCC to make this work, you can also VPN in, then your network connection is within the VCC and it will work. I have VPNed in, while on campus in the Union to get LDAP to work.
After much tinkering with RPI’s CAS (Central Authentication System) in PHP, I thought I would put together a guide to make it easy for anyone to put together a site that uses it. This would work for anyone at another location with a CAS server, but this example is for RPI.
Download “cacert.pem”, and put it in root of web project
Create a index.php, login.php, logout.php
The index has to load the library, check if the user is logged in, then print out text.
<?PHP
include_once(“./CAS-1.3.2/CAS.php”);
phpCAS::client(CAS_VERSION_2_0,’cas-auth.rpi.edu’,443,’/cas/’);
// SSL!
phpCAS::setCasServerCACert(“./CACert.pem”);//this is relative to the cas client.php file
First we load the library for CAS from the subfolder
Then we select which will be our central server
We have to select our ca bundle, setCasServerCert does this
Now we have fully loaded and configured the library
Finally, I can ask CAS if a user has logged in, if so writeout some options, if not others
This is the login page
<?PHP
include_once(“./CAS-1.3.2/CAS.php”);
phpCAS::client(CAS_VERSION_2_0,’cas-auth.rpi.edu’,443,’/cas/’);
// SSL!
phpCAS::setCasServerCACert(“./CACert.pem”);//this is relative to the cas client.php file
if (!phpCAS::isAuthenticated())
{
phpCAS::forceAuthentication();
}else{
header(‘location: ./index.php’);
}
?>
Similar setup of authentication as before
Now we check if the user is NOT authenticated, if the user is not authenticated we force login
If the user already is logged in, then we redirect to the index
The logout page:
<?PHP
include_once(“./CAS-1.3.2/CAS.php”);
phpCAS::client(CAS_VERSION_2_0,’cas-auth.rpi.edu’,443,’/cas/’);
// SSL!
phpCAS::setCasServerCACert(“./CACert.pem”);//this is relative to the cas client.php file
if (phpCAS::isAuthenticated())
{
phpCAS::logout();
}else{
header(‘location: ./index.php’);
}
?>
Same configuration (this can be done by including a core file that everything else calls, but for this example I wanted to keep it simple)
If they are not logged in, then we push the user back to login
That is the basic configuration, the example is available for download below. If there are any questions feel free to post a comment.
Recently there was a big update the to QuickLogs product, on the face of it, it looks like the buttons have been changed a little bit. That is the small part of the upgrade, the main change is how the stats page works. Now the stats page is run by the HighCharts JavaScript engine instead of the PHP libchart that was used in the past. This takes the load of creating charts off of the server, and moves it to JavaScript Also this increases the flexibility to add more charts in the future.
I started the new stats page (v3.3.0) with a drop down to select different types of graphs, the Activities, User, and Overall graphs were used with the drop down. A quick comment made by people at the Helpdesk was “why not use all the space available, I dont like having to navigate again after refreshing.” v3.3.1 brought back the single page, but more importantly sorted the data in the charts. By default Highcharts plots by order the data is put into it; but it was not largest category to smallest. A quick sort was put in, and then we were back to where v3.2 ws with charts but a new engine. The new engine also allows for the charts to be looked at under different time periods instead of only 30 days.
The morning the program moved to version 3.3.2, this was a pure bug fix with CAS having a certificate issue under the login page. At this time, I decided to centralize the CAS information for all pages under the ‘core.php’ page. That way if the certificate moves there is one place to do it.
QuickLogs represents a early version of my app design; these days I tend to make core.php and ajax.php heavy with most of the application functions, and subsequent pages call them with ajax. This is a older app where a lot of the functions are hard coded in the page. I have started migrating to using a wrapper on MySQL like I have with the time cards app. But I only changed it on functions I was modifying so most of QuickLogs remains doing manual queries.
Looking to the future there are many ideas for QuickLogs, yet little time to compete them. One person suggested a achievement system for different things you can do at work. Another suggestion was a Nemesis a person who is right ahead of you for tickets, and having competition. The final suggestion was for some different types of charts. I wanted to do charts, I just have to find time.
At this point, QuickLogs is going on the shelf. (Unless I get a itch to add more charts) I am shifting to more time on Time Tracker and getting this product finished, before I leave RPI. Documentation for both products should be updated soon as well.
Recently I have been working on an hour keeping system for my work at RPI; we have an old time card system that is running on a Windows 2000 server. The code no longer works, as in the JavaScript is not supported by modern browsers. The old system has been running for over 11 years, and it is time to let it retire.
The new system is at version 0.1 right now, with basic functionality working. The system is split into groups, so while one server runs separate departments can run a “group” and have their employees under there. Once a user is given privileges to one group in the system, when that user logins in, that group will automatically come up.
The old system had a html page that managers could edit, to give announcements to workers. This was a bit of a tedious process to go in and manually edit these pages, now there is a field for the manager of each group to drop html to edit their page. The system has two levels of accounts and privileges, there is the privilege within a group, and the privilege for the entire system. While a user can be administrator of a group and edit their group, they may not have administrative rights over the entire server. By having administrative rights to the entire server, a user can change the splash page before a user is logged on, or create new groups in the system.
The system allows for templates to be made of weeks, so if a student worker works the same hours every week, then they can save it and deploy it easily. I am working on integrating email reminders by using a .Net application that integrates with MySQL. By having the application read who has yet to enter logs this pay period I can use the students CAS login to get their email.
Below are some photos of the system, and it is all open source at the attached link.