Friday, 22 August 2008

Grails - JSecurity plugin

JSecurity is a Grails plugin that adds authentication and authorization to a web application. First we go about creating a project and installing the plugin:

grails create-app project_name
grails install-plugin jsecurity

Then we use the quick-start option, available once the plugin is installed, to generate JSecurity domain classes, controller and realm.

grails quick-start

We can follow the JSecurity Quick Start guide to create a functional security application or use the files present to customize and only take what is required.

Authentication


For the login authentication, we'll need the User class, the Auth controller and the DbRealm.

  • The User class will need a username and password field. The password field must be hashed, SHA1 is the default.

  • For the Auth controller, the important methods are signIn and signOut. For signIn, the important lines are the authToken definition, the jsecSecurityManager login and the try-catch block.

  • Authentication occurs in the DbRealm. The important lines in the authenticate method are the account definition and the credentialMatch. You may customize the authToken class by changing the static line, replacing the default with your own class.

  • credentialMatch defaults to SHA1 hashing, to change it, modify grails-app/conf/spring/resources.groovy and add the line credentialMatcher(org.jsecurity.authc.credential.hashMatcher). Replace hashMatcher with the hash class of your choice.


Roles


Roles depend on the hasRole method of the realm. This method accepts a principal, usually a username, and a rolename. The output is a simple true or false boolean, making the logic inside the method completely up to the programmer. The classes generated by the quick-start are not all necessary. We can easily use a variable in the user class to determine the role, modifying the hasRole method as required, thus no additional classes are needed.

For this project, we are using the default hasRole method and keeping the Role as well as the UserRoleRel class. This, along with the User class, allows us to have users and roles, assigning the users to a role in a many-to-one relationship. Refer to the JSecurity Quick Start guide for the way to bootstrap it.

Authorization


Having users and roles, we can now set up proper access control by creating a security filter file, grails-app/conf/SecurityFilters.groovy. Filter rules cannot overlap in actions, just modify the accessControl to include the desired roles. The rules return true or false, allowing or denying access.

Security Filter Example

import org.jsecurity.SecurityUtils
// Customise the interceptor behaviour by implementing onNotAuthenticated() and onUnauthorized() methods in your filters class.
// Default behaviour remains as before (redirect to login page for an unauthenticated user, redirect to unauthorized page for unauthorized access).
class SecurityFilters {
def filters = {
// Ensure that all controllers and actions require an authenticated user,
// except for a few controllers
auth(controller: "*", action: "*") {
before = {
// Exclude these controllers.
if ((controllerName == "search" && actionName == "unboundSearch") || (controllerName == "business" && actionName == "show") ||
(controllerName == "user" && actionName == "signup")) return true

// This just means that the user must be authenticated. He does
// not need any particular role or permission.
accessControl { true }
}
}

// Roles return true or false
// Add reviews to businesses. Only Administrators or Users can do this
addReview(controller: "review", action: "create") {
before = {
accessControl {
role("Administrator") || role("User")
}
}
}

// Add pets to users
addPets(controller: "pet", action: "(create|save)") {
before = {
accessControl {
def user = User.findByUserName(SecurityUtils.subject.principal)
def allowAccess = false

if (role("Administrator")) {
allowAccess = true
}
else if (params.id.toLong() == user.id) {
allowAccess = role("Business User") || role("User")
}
return allowAccess
}
}
}
}
}

Permissions


Permissions offer finer access control, like read, update, delete. Roles can be considered as named collections of permissions, like administrator, user, superuser. Nothing was done with permissions, it was entirely a role-based affair. Refer to the documentation for usage.

Links


Wednesday, 16 July 2008

GSP training

Brought Fauzan up to speed on the project work that's been done, explaining the search controller and the gsp code.

He made a simplified version of the search page, recreating the basic functionality.

The CSS was not touched on. I figure one can just strip it from the page and into a file then figure out where to put and call the file.

Similarly the javascript, dealing with the Google map functionality, may be moved to a file and referred to. It may not work due to the gsp tags inside the code.

Thursday, 26 June 2008

TWiki Replication

Setup a backup TWiki by using rsync, cron and public key authentication. Had problems getting cron to run on root since a normal user does not have the permissions necessary. Solved them when I realized I do need the account active (as I had ignored the expired warning when logging in as root).

Made little headway with regards to the MixTape build on hudson (reminder: change the SVN location once migration is finished). Installed the Flex 3 SDK and used it to compile the mxml files. However the swf files do not seem to work.

The grails search plugin sets up easily. Run 'grails install-plugin searchable', add 'static searchable = true' to any domain class, add data and run the app. The default allows you to search the fields of the domain class, objects may need a specific mapping though.

In the process of migrating SVN projects from one repository to another.

Wednesday, 28 May 2008

Flex File Upload using Grails Backend

This file upload application is based off the one by Nocturnal at Coding Cowboys, a Flex client with a PHP backend. The client has been stripped down to it's core functions and PHP replaced with a Grails backend.

The Grails backend is a file controller with an action defined:

def upload = {
if(request.method == 'POST') {
Iterator itr = request.getFileNames();

while(itr.hasNext()) {
MultipartFile file = request.getFile(itr.next());
File destination = new File(file.getOriginalFilename())

if (!file.isEmpty()) {
file.transferTo(destination)
// success
}
else
{
// failure
}
}

// Trigger an Event.COMPLETE event, notifying the Flex client
response.sendError(200,'Done');
}
}


This is capable of uploading multiple files at once and can be tested using a view gsp:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="layout" content="main" />
<title>Test Upload</title>
</head>
<body>
<div class="body">
<h1>Upload File</h1>
<g:form method="post" action="upload" enctype="multipart/form-data">
<input type="file" name="file_1"/><br/>
<input type="file" name="file_2"/><br/>
<input type="file" name="file_3"/><br/>
<input type="file" name="file_4"/><br/>
<input type="file" name="file_5"/><br/>
<input type="submit"/>
</g:form>
</div>
</body>
</html>


The Flex client has been pared down to 3 main functions, adding files to the upload list, removing them from the list and finally uploading the files to the server.

First the imports, global variables and initializer:

import mx.controls.*;
import mx.managers.*;
import mx.events.*;
import flash.events.*;
import flash.net.*;

// Convention: Underscore to differentiate global and local variables
private var _refAddFiles:FileReferenceList;
private var _refUploadFile:FileReference;
private var _arrUploadFiles:Array;
private var _numCurrentUpload:Number;

private function initApp():void {
_refAddFiles = new FileReferenceList();
_refAddFiles.addEventListener(Event.SELECT, onSelectFile);
_arrUploadFiles = new Array();
_numCurrentUpload = 0;
}


The add-files function opens the browse window and enable the selection of one or more files to add to the upload list:

// Called to add file(s) for upload
// The fileList property is populated anew each time browse() is called on that FileReferenceList object.
private function addFiles():void {
_refAddFiles.browse();
}

// Called when file(s) are selected
private function onSelectFile(event:Event):void {
// Add files to _arrUploadFiles
if (_refAddFiles.fileList.length >= 1) {
for (var k:Number = 0; k < _refAddFiles.fileList.length; k++) {
_arrUploadFiles.push({
name:_refAddFiles.fileList[k].name,
size:formatFileSize(_refAddFiles.fileList[k].size),
file:_refAddFiles.fileList[k]});
}
listFiles.dataProvider = _arrUploadFiles;
listFiles.selectedIndex = _arrUploadFiles.length - 1;
}
}


The remove-files function:

private function removeFiles():void {
var arrSelected:Array = listFiles.selectedIndices;
if (arrSelected.length >= 1) {
// Null selected files
for (var i:Number = 0; i < arrSelected.length; i++) {
_arrUploadFiles[Number(arrSelected[i])] = null;
}

// Remove the null entries
for (var j:Number = 0; j < _arrUploadFiles.length; j++) {
if (_arrUploadFiles[j] == null) {
_arrUploadFiles.splice(j, 1);
j--;
}
}
listFiles.dataProvider = _arrUploadFiles;
listFiles.selectedIndex = 0;
}
}


The upload function is where the point of integration with Grails is, in the request calling up the controller. Although the Grails backend can handle multiple files, Flex can only initiate the upload one file at a time. The event listener and the return response in the Grails controller allow the upload function to loop:

private function uploadFiles():void {
if (_arrUploadFiles.length > 0) {
listFiles.selectedIndex = _numCurrentUpload;

var request:URLRequest = new URLRequest();
request.data = sendVars;
request.url = "http://localhost:8080/App/file/upload";
request.method = URLRequestMethod.POST;
_refUploadFile = new FileReference();
_refUploadFile = listFiles.selectedItem.file;
_refUploadFile.addEventListener(Event.COMPLETE, onUploadComplete);
_refUploadFile.upload(request, "file", false);
}
}

private function onUploadComplete(event:Event):void {
_numCurrentUpload++;
if (_numCurrentUpload < _arrUploadFiles.length) {
uploadFiles();
} else {
_numCurrentUpload = 0;
_arrUploadFiles = new Array();
listFiles.dataProvider = _arrUploadFiles;
listFiles.selectedIndex = 0;
Alert.show("Files have been uploaded", "Upload Complete");
}
}


And lastly the UI:

<mx:Panel title="Files Upload" width="100%" height="100%">
<mx:DataGrid id="listFiles" allowMultipleSelection="true" verticalScrollPolicy="on"
draggableColumns="false" resizableColumns="false" sortableColumns="false" width="100%" height="100%">
<mx:columns>
<mx:DataGridColumn headerText="File" dataField="name" wordWrap="true"/>
</mx:columns>
</mx:DataGrid>

<mx:ControlBar>
<mx:Button label="Add" click="addFiles()"/>
<mx:Button label="Remove" click="removeFiles()"/>
<mx:Button label="Upload" click="uploadFiles()"/>
</mx:ControlBar>
</mx:Panel>


The Flex mxml/swf files must be moved to the web-app folder of the Grails project and the embedded Jetty activated by 'grails run-app' in order to run this application.

The files will be uploaded to the project directory and thus are not accessible by the webapp. The line to amend is in the Grails controller:

File destination = new File("web-app/" + file.getOriginalFilename())

Note this only works while the project is in development mode. For war files, the base directory would depend on where the server is started, usually in the server home directory. So for a standalone Jetty server, the path to add would be "webapps/App/".

Using the war file in a Tomcat server has been problematic. Only one file can be successfully uploaded to the server, there is no looping.

Links:
Coding Cowboys: Flex upload component

Flex Client:
http://livedocs.adobe.com/flex/3/langref/flash/net/URLRequest.html
http://livedocs.adobe.com/flex/3/langref/flash/net/FileReference.html
http://livedocs.adobe.com/flex/3/langref/flash/net/FileReferenceList.html
http://livedocs.adobe.com/flex/3/html/help.html?content=17_Networking_and_communications_7.html

Grails Backend:
http://www.grails.org/Controllers+-+File+Uploads
http://docs.codehaus.org/display/GRAILS/File+Upload

Friday, 23 May 2008

Flex Training - Last bit

Used list-based controls that accept a data array and display out depending on design. Then dealt with data forms, accepting user input, validating it and supposedly entering it into the database.

The last bit was how to create a release version of the Flex application.

Thursday, 22 May 2008

Flex Training - Dynamic Data

Read an XML file using a HTTPService and displayed it. Autogenerated a PHP XML service based on database contents previously inserted. The Flex application was supposed to use the service to access the data in the database and display it on the page. However seems there's a problem with the service.

The videos make use of MAMP, a Mac-Apache-MySQL-PHP all-in-one webserver. There may be conflicts with the MySQL that was previously installed and the MAMP's version.

Wednesday, 21 May 2008

Flex Training - Debugging and Event Handling

Debugging - How to set breakpoints and traces (logging to console). The breakpoints suspend the application, allowing one to see the variables and objects present at that particular time.

Event Handling - Dealing with events and how to listen for them. One can also create custom events. With a breakpoint, the anatomy of an event can be explored, showing the specific variables and the inherited ones that make up the event.