Ever wondered who is currently logged in to your app or how to kick them out? . You can do it using SessionRegistry.
(Disclaimer: UI is self-coded, not provided by Spring)
First, setup spring security configuration
Java config:
.and()
.sessionManagement()
.maximumSessions(1) // How many session the same user can have? This can be any number you pick
.expiredUrl("/login?expired")
.sessionRegistry(sessionRegistry)
And register the sessionRegistry bean:
(name = "sessionRegistry")
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
Or XML config, place this below :
Now you can list currently active sessions
Inject a SessionRegistry and let’s see who’s currently logged in:
private SessionRegistry sessionRegistry;
public List getActiveSessions() {
List activeSessions = new ArrayList<>();
for(Object principal : sessionRegistry.getAllPrincipals()) {
activeSessions.addAll(sessionRegistry.getAllSessions(principal, false));
}
return activeSessions;
}
Principal is just a fancy word for user in security speak. Note how SessionInformation returns a principal of type Object. If you use Spring Security your principal will most likely be the type of org.springframework.security.core.userdetails.User
Here’s how you can get the username from a User object:
SessionInformation session = ... // get the session info somehow
Object principalObj = session.getPrincipal();
if (principalObj instanceof User) {
User user = (User) principalObj;
return user.getUsername();
}
If you need to kick someone out
The use case of this is not just for when you hated a particular user so much, but if user permission is updated, then you have to invalidate all active sessions for it to take effect.
public void logoutSession(String sessionId) {
SessionInformation session = sessionRegistry.getSessionInformation(sessionId);
if (session != null) {
session.expireNow();
}
}
Here’s how we all used to make it safer in Java 7 <
String city;
Person person = personRepository.getByUsername("bob");
if (person != null) {
Address address = person.getAddress();
if (address != null) {
city = address.getCity();
if (city == null) {
city = "Unknown";
}
}
}
Java 8 lambda to the rescue:
String city = personRepository
.findByUsername("bob")
.flatMap(Person::getAddress)
.flatMap(Address::getCity)
.orElse("Unknown")
;
How does this work? flatMap and orElse are methods of Optional interface. In plain english flatMap(Person::getAddress) reads: apply the function getAddress belonging to the class Person and give me whatever return value getAddress has.
Of course we have to wrap the types used to store the values in the object with Option:
public class PersonRepository {
public Option findByUsername(String username) {
...
}
}
public class Person {
private Option address;
public Option getAddress() { return this.address; }
}
public class Address {
private Option city;
public Option getCity() { return this.city; }
}
No way! I don’t want to have to wrap all my property types with Optional / I’m using a 3rd part library and cannot refactor the types
Not a problem you can wrap them when you traverse the object:
String city = Optional.ofNullable(personRepository.findByUsername("bob"))
.map(Person::getAddress)
.map(Address::getCity)
.orElse("Unknown");
;
Optional.ofNullable will create an Optional object with values that may be null. map is similar to flatMap except this one says: apply function X to this Optional and give me another Optional with whatever X’s return type.
One more reason to convince your boss / architect / team lead to upgrade your code into Java 8 :-). Enjoy.
This setup only works assuming you have on your main configuration class. By default Spring Security will provide a login form at /login but you can implement your own. I’ve also setup two users to test it
The Web MVC auto configuration feature of Spring Boot sets you up with a ViewResolver with blank suffix and prefix, hence you can place jsp in src/main/webapp/WEB-INF/test.jsp and have your controller return path to it
("/test")
public class TestController {
(method = GET)
public String test() {
return "/WEB-INF/test.jsp";
}
}
Suppose you have a Student and Subject entities and you want to create a many-to-many relationship between them. The database table looks something like this:
(name = "students")
public class Student {
@Id
private long id;
private String name = "";
(cascade = CascadeType.All)
(name = "students_subjects",
joinColumns = (name = "student_id", referencedColumnName = "id"),
inverseJoinColumns = (name = "subject_id", referencedColumnName = "id"))
private Set subjects = new HashSet();
/* getters, setters, equals & hashCode */
}
Note how I used CascadeType.All above, this will case any modification to subjects collections to be cascaded automatically when I saved the student entity object.
Also note the use of Set collection instead of List. This will prevent duplicates when querying since JPA wouldn’t know whether the multiple rows are a result of join or simply multiple entries in the result.
And here’s the Subject JPA entity:
(name = "subjects")
public class Subject {
@Id
private long id;
private String name = "";
(cascade = CascadeType.All)
(name = "students_subjects",
joinColumns = (name = "subject_id", referencedColumnName = "id"),
inverseJoinColumns = (name = "student_id", referencedColumnName = "id"))
private Set students = new HashSet();
/* getters, setters, equals & hashCode */
}
Note that the annotation on Subject is similar to Student except the joinColumns and inverseJoinColumns are reversed.
Also since the above example uses HashSet, don’t forget to implement proper equals and hashCode methods.
Spring Security comes handy when you need to secure your RESTful web service. Let’s give this a go! In this example I’ll create a REST service exposing a Cat entity. It simply have name and colour field
{
"name" : "Tom",
"colour" : "Black"
};
Creating the Service
Setup a new maven project with following pom.xml. We’ll leverage Spring Boot to simplify the work.
Setup a main configuration class. This substitutes the old-fashioned spring context xml. Spring Boot will do a lot of under-the-hood work to setup various bits and pieces using auto configuration
guration
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
Now let’s create our Cat JPA entity
public class Cat {
@Id
private long id;
private String name = "";
private String colour = "";
/* .. getters & setters omitted .. */
}
Since we included dependency to spring-boot-starter-data-jpa, Spring Boot will automatically set us up with JPA with Hibernate implementation. Also note that on pom.xml we declared a dependency to hsqldb which will automatically give us datasource to an embedded HSQL database.
Next, let’s create a Spring Data repository for Cat.
esource
public interface CatRepository extends PagingAndSortingRepository {
}
Again, spring-boot-starter-data-jpa will auto setup spring-data-jpa for me, and it will automatically provide an implementation of the repository interface at runtime.
Take a note at the esource annotation. This annotation tells Spring Data REST to expose the repository as REST service as well.
Testing the Service
Now you’re ready to run the app using the embedded tomcat container. Run following maven command
Next, configure Spring Security so /cats/** path are protected to users with ROLE_USER only. We also setup two in-memory users: bob with ROLE_USER and admin with ROLE_USER and ROLE_ADMIN
Don’t forget to recompile and restart the app. Now you can test querying the cats repository will be forbidden for non-authenticated (anonymous) users:
The -H option passes a HTTP header as part of the request. Also note that the username and password joined by colon (:) is encoded into Base64 resulting in the string Ym9iOmJvYjEyMw==. This is the string “bob:bob123″ in plain text. You can use an to try it yourself.
Also note that similar to web browser the server gave us a JSESSIONID Cookie:
Different Security Permission for Read / Update Operations
What if you want to give ROLE_USER read-only access and full read/write to ROLE_ADMIN?
This can be achieved by using Spring Data Repository event handler class. You can invoke custom code prior / after certain operations executed on the repository. Let’s see how this works.
First enable method security on our SecurityConfig class. Add the hodSecurity(securedEnabled = true) annotation to SecurityConfig class:
ty
hodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
}
Create a new CatEventHandler class annotated with Handler(Cat.class)
Handler(Cat.class)
("ROLE_ADMIN")
public class CatEventHandler {
private static final Logger LOG = LoggerFactory.getLogger(CatEventHandler.class);
e
public void handleBeforeSave(Cat c) {
LOG.debug("Before save " + c);
}
ate
public void handleBeforeCreate(Cat c) {
LOG.debug("Before create " + c);
}
kSave
public void handleBeforeLinkSave(Cat c) {
LOG.debug("Before link save " + c);
}
ete
public void handleBeforeDelete(Cat c) {
LOG.debug("Before delete " + c);
}
kDelete
public void handleBeforeLinkDelete(Cat c) {
LOG.debug("Before link delete " + c);
}
}
Few important things happening here:
All the .. methods will be invoked before the corresponding response is given to users
The (“ROLE_ADMIN”) annotation will ensure only users with ROLE_ADMIN can invoke all those methods in the class (although the method has nothing in it except a logging statement)
Let’s give this a try. Authenticate as bob:bob123 again and try creating a new Cat. Error will be presented:
I find it annoying to keep having to encode our username and password into Base64. I wanted a more simplified login such as posting u=bob&p=bob123 to http://localhost:8080/login.
Let’s try doing this.
Borrowing idea from , let’s create a LoginController
("/login")
public class LoginController {
private SecurityConfig securityConfig;
private AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource();
private static final Logger LOG = LoggerFactory.getLogger(LoginController.class);
(method = RequestMethod.POST)
public String login(("u") String username,
("p") String password,
HttpServletRequest req) throws Exception {
// Force session creation so it's available to Spring Security post processor filter
req.getSession(true);
// Authenticate using AuthenticationManager configured on SecurityContext
AuthenticationManager authMgr = securityConfig.authenticationManagerBean();
UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken(username, password);
authReq.setDetails(authenticationDetailsSource.buildDetails(req));
Authentication authResp = authMgr.authenticate(authReq);
// If successful add the authentication response to context so the post processor filter
// can save it to session
SecurityContextHolder.getContext().setAuthentication(authResp);
return "Authentication successful";
}
...
}
Also create some exception handlers so login failure will produce 401 – Unauthorized HTTP status code.
Yay! Well done on making it this far. Hope you get a pretty decent looking REST API with minimal effort thanks to Spring. Don’t forget to always serve your API in HTTPS if deploying in production environment and secure it further with firewall if applicable.
As always you can browse the source code of this article on github:
I’ve been programming Java for almost 8 years now and I still haven’t fully figured out this logging problem. Log4j, slf4j, commons-logging, JCL, JUL, logback… Why are there so many? Does this really have to be so complicated? How did we end up here? Which logging framework to use?
Let’s try to start from a humble beginning. This is essentially the problem we’re trying to solve:
System.out.println("Hello world!");
Yes.. logging is all about getting your code to produce some sort of text when an interesting event happen. The value of this can be priceless, especially when you’re debugging your code, or monitoring a production environment.
So what’s wrong with System.out.println
System.out.println is probably the easiest and most widely used logging ever, and thank God for it has taught so many new programmer how to print a text to console. But printing to console alone is not good enough, since a console can only hold so much information and the information get wiped out pretty quickly.
Also depending on the stage of your software development, a logging statement might (no longer) become useful. A System.out.println("YES this function is called"); is very useful early when you’re still writing your code, but you don’t want it to keep printing once it’s deployed to production, and you don’t want to have to recompile your code just to add/remove logging statement. Trust me, in some (poorly managed) organisations you’d be amazed to see how much fear, hysteria, anxiety and stress people get just by hearing the fact that you need to “recompile and release new version of the code”.
Enter the world of logging library
Hence why we use logging libraries. Common features of logging libraries are:
Ability to assign LEVEL to your logging statement to indicate the urgency of the statement
To filter logging statement only from specific subset of modules / level
And to configure where the output goes: console, text file, database, etc
Here’s an example of logging statement being printed by a class:
import org.apache.log4j.Logger;
public class FiddleService() {
private static final Logger LOG = Logger.getLogger(FiddleService.class);
public void doFiddle() {
LOG.debug("fiddling..");
}
}
As you can see the class above is explicitly dependant upon log4j logging library. Apart from log4j, JUL (Java Util Logging)
Good developers don’t reinvent the wheel
Yes, we Java developers don’t like reinventing the wheel. Being one of the first cross-platform language, Java really took this concept to the next level since all of a sudden everyone can write libraries regardless what OS / processor / computers they’re running, and that library become usable by everyone else.
However sometimes this creates a situation where the same problem being solved multiple times by several competing libraries. Logging is one good example of this.
Logging libraries are unique in the sense that almost all other libraries depend on a logging library of some sort. And the lack of built-in logging abstraction in Java itself has caused all this mess.
Let’s highlight this problem with some example
My awesome app uses two libraries: meow and purr. meow uses log4j for logging, and purr uses JUL (Java Util Logging). As a result now my app pulls log4j (JUL is included in JDK) transitively. If I wanted to show certain statement, I have to constantly ask the question “Hmm.. what logging library does XYZ uses again?” which is horrifying (Consider a typical java project with 40 dependency jars).
Logging Facade
So to solve this problem, Logging Facade is invented. A logging facade is not a logging library by itself, but it’s just a set of interface that allows program to interact with any logging libraries.
Logging facade allows the client application to choose whatever logging provider, and simply “bridges” the logging output there. Here’s previous example refactored with slf4j logging facade:
Note that here slf4j bridges the logging into log4j, but this is entirely configurable. You can use JUL, logback or any other libraries you like.
So if you are asking yourself, or has been asked “which logging framework to use”. I’d say the answer is slf4j. Not because it’s the best, but simply because it’s a (most widely used) facade — it allows you (or your users/customers/clients) to use whatever logging implementation they please.
In my app I have lots of scheduled service classes implemented like this:
public FiddleService {
private TaskScheduler scheduler;
private void setupScheduler() {
Runnable task = new Runnable() {
public void run() {
letsFiddle();
}
};
scheduler.scheduleAtFixedRate(task, 10 * 1000);
}
public void letsFiddle() {
...
}
}
At first the structure looked relatively simple, the scheduler will call letsFiddle() every 10 seconds. AOP-transaction wise I thought this should be okay since I used AspectJ mode (instead of JDK proxy).
But I just discovered this is wrong! The annotation was not effective if it’s invoked inside an inner-class.
Yep I only figured this out when strange transaction related behaviour started occuring in my app.
Few trials and errors, and I figured out the best way to implement this is to always separate the task in its own class:
public class FiddleService {
public void letsFiddle() {
...
}
}
public class FiddleServiceScheduler {
private TaskScheduler scheduler;
private FiddleService fiddleService;
private void setupScheduler() {
Runnable task = new Runnable() {
public void run() {
fiddleService.letsFiddle();
}
};
scheduler.scheduleAtFixedRate(task, 10 * 1000);
}
}
This will ensure all construction-related work is done on FiddleService (possibly AOP-tx related stuff) before we invoke its transactional method
Here’s my situation, I have myapp.firstdomain.com and myapp.seconddomain.com and I want my app to be styled / branded differently according to which domain used to access the app.
To keep things simple, each theme would have its own properties file with corresponding values. For example:
Next we have to register a ResourceBundleThemeSource. This tells spring where the theme specific properties file are located (in this instance we place them on themes/ folder on classpath root).
In Spring Boot, since I used automatic configuration for the web application context, additional customization has to be done via WebMvcConfigurerAdapter
public class WebMvcConfig extends WebMvcConfigurerAdapter {
public ThemeSource themeSource() {
ResourceBundleThemeSource themeSource = new ResourceBundleThemeSource();
themeSource.setBasenamePrefix("themes/");
return themeSource;
}
}
Next I need to create a ThemeResolver bean that can determine the theme based on domain names. In this instance since I used a reverse proxy, I used X-Forwarded-For HTTP header to determine the hostname, but you can simply use Host header otherwise.
This ThemeResolver keeps a map of which domain transaltes to what theme.
public class DomainNameThemeResolver extends AbstractThemeResolver {
private Map domainNameThemeMap = new HashMap();
public String resolveThemeName(HttpServletRequest request) {
String xFwdFor = request.getHeader("x-forwarded-for");
if(xFwdFor == null) {
return getDefaultThemeName();
}
String themeName = domainNameThemeMap.get(xFwdFor.trim().toLowerCase());
if(StringUtils.isBlank(themeName)) themeName = getDefaultThemeName();
return themeName;
}
public void setThemeName(HttpServletRequest request, HttpServletResponse response, String themeName) {
}
public Map getDomainNameThemeMap() {
return domainNameThemeMap;
}
public void setDomainNameThemeMap(Map domainNameThemeMap) {
this.domainNameThemeMap = domainNameThemeMap;
}
}
And finally, back to the WebMvcConfigurerAdapter, I also need to register this ThemeResolver bean
public ThemeResolver themeResolver() {
DomainNameThemeResolver themeResolver = new DomainNameThemeResolver();
themeResolver.setDefaultThemeName("firstdomain");
themeResolver.getDomainNameThemeMap().put("myapp.firstdomain.com", "firstdomain");
themeResolver.getDomainNameThemeMap().put("myapp.seconddomain.com", "seconddomain");
return themeResolver;
}
The theme-specific key value pairs can then be obtained on the thymeleaf view using the special #themes.code(...) syntax. Here’s an example:
Note that if you’re debugging your theme resolver, Spring won’t actually invoke the resolveTheme() method unless you are actually rendering a view that needs one (eg: a jsp view that contain tag).
By default Spring Boot will source messages src/main/resources/messages.properteis. Specific translations for various languages can be given using the file messages_ch.properties, messages_es.properties etc. This location can be adjusted using spring.messages.basename property. See MessageSourceAutoConfiguration class for more.
Using message is a handy way to externalize something from your view. If you’re using JSP, you can inject this value like this:
The app version is ${version}
Or in thymeleaf, it can be obtained directly using hash dialect:
The app version is
Gerry's software development journey of trial, errors and re-trials