JavaFX in Spring Day 3 – Authentication and Authorization
Join the DZone community and get the full member experience.
Join For Freewelcome to day 3 of the javafx in spring blog series. in this post we are going to finish off the customer data application by taking advantage of the spring security apis on the client.
it took a little bit of hacking, but i got a github project put together with a straightforward javafx maven build (details on this in a future post) to run everything. please give the full project a view and run it from source so you can experiment with the application as you read this post:
for easy reference, you can flip to any of the blogs here:
- javafx in spring day 1 – application initialization
- javafx in spring day 2 – configuration and fxml
- javafx in spring day 3 – authentication and authorization
since my last post i made it out to two additional user groups in texas, and had a great time speaking at both:
on the left is the austin jug , which is a large, well-established user group and on the right is the houston jug , which had a unique venue with personal monitors for all the attendees (this would be a great setup for a lab in the future!) i posted the talks on hacking javafx with groovy, clojure, scala, and visage and javafx 2 – a java developer’s guide to slideshare so they can grab the full presentation decks.
getting back to the javafx in spring example, in the last blog we covered spring configuration of a javafx app to modularize the screens. as a simple example we did an error dialog to show how fxml ties in, but now let’s create a login page to demonstrate using spring security for authentication.
the login dialog was created visually in scenebuilder and the final version ended up looking like this:
(since the first post i added in a few convenience hyperlinks for logging in as an employee or a manager)
and the controller code is as follows:
public class logincontroller implements dialogcontroller { @autowired private authenticationmanager authenticationmanager; @autowired private screensconfiguration screens; private autowirefxmldialog dialog; public void setdialog(autowirefxmldialog dialog) { this.dialog = dialog; } @fxml label header; @fxml textfield username; @fxml textfield password; @fxml public void login() { authentication authtoken = new usernamepasswordauthenticationtoken(username.gettext(), password.gettext()); try { authtoken = authenticationmanager.authenticate(authtoken); securitycontextholder.getcontext().setauthentication(authtoken); } catch (authenticationexception e) { header.settext("login failure, please try again:"); header.settextfill(color.darkred); return; } dialog.close(); screens.showscreen(screens.customerdatascreen()); } @fxml public void employee() { username.settext("employee"); password.settext("lol"); } @fxml public void manager() { username.settext("manager"); password.settext("password"); } }
the important part for authentication is taken care of in the login method. this grabs the username and password from the respective fields and creates a new usernamepasswordauthenticationtoken. to force authentication to take place immediately, we get autowire a reference to the spring authenticationmanager and call the authenticate method. if the user exists in our credential store the method will succeed, otherwise it will throw an authenticationerror we catch in the enclosing try block.
for the purpose of this example we are using a local authentication store in the spring xml config. you could easily hook up to an ldap server or your chioce of authentication engines, but this makes the sample app we are building self contained. here is the spring config xml:
<?xml version="1.0" encoding="utf-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:security="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> <security:global-method-security secured-annotations="enabled"/> <security:authentication-manager> <security:authentication-provider> <security:password-encoder hash="plaintext"/> <security:user-service> <security:user name="manager" password="password" authorities="role_manager"/> <security:user name="employee" password="lol" authorities="role_employee"/> </security:user-service> </security:authentication-provider> </security:authentication-manager> </beans>
this sets up two different users and two roles. one is our manager who will have full access to the system and a laughably weak password, and the second is the employee who will only only have access to create new customers, but not delete. we are going to take advantage of these roles to secure the customer creation and deletion routines using annotation-based authorization.
now that annotations-based configuration is setup, you can secure methods in your application by simply adding an appropriate annotation to it as shown in this code snippet from customermodel:
@secured("role_manager") public void remove(customer customer) { resttemplate.delete("http://localhost:8080/crm/customer/" + customer.getid()); customers.remove(customer); }
any time this method is called, you will get an exception thrown that will prevent that method from getting executed and can be caught to give good user feedback, such as an error dialog:
to finish off the example, here is a screenshot of the completed example that includes a javafx table for displaying elements that are pulled back from the server using the spring resttemplate api:
and again, you can find the full code available for download here:
browse project on github
now that i have shown you how you can take advantage of spring in your javafx applications, it is only fair to point out some of the shortcomings you may encounter:
- jar explosion – i tried to be minimalistic in my inclusion of dependencies, but still ended up with dozens of jar files for this example application. this may be an issue if you are deploying to resource constrained devices or over a thin network pipe, but for packaged applications should not be an issue.
- all permissions required – since spring makes heavy use of aspect-oriented programming (aop) libraries that manipulate bytecode, you won’t be able to run this application in the java sandbox. the best approach is to request all permissions and code sign your application so the end user just gets prompted once.
- aop glitches – in your own applications you will trip across various little quirks with aop and bytecode manipulation that can make client programming quite hazardous. for example, if you put an @secured annotation in a ui class file loaded in the main thread, you will get a classcastexception on the proxy. it is possible to get the target class out like this , but it is nefarious enough that it bit me in a live-coding presentation.
hopefully you have learned a little bit through this tour of javafx and spring integration. i would love to hear what other folks have been doing to integrate these technologies in the comments section below.
Published at DZone with permission of Stephen Chin, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments