Tuesday, 3 June 2014

How to add JasperReports library to Gradle project

Usually adding new dependency is enough to add new library to Gradle project.

Unfortunately this is not that case.

To properly add JasperReports library we have to deal with compiling reports (new ant task) and adding new repositories.

New repositories


Standard repositories section look like this:

1
2
3
4
repositories {
 mavenLocal()
 mavenCentral()
}

JasperReports needs two additional repositories. It is because guys who develop this library often publish fixes to third-party libraries.
Our repositories section should look like this:

1
 2
 3
 4
 5
 6
 7
 8
 9
10
repositories {
 mavenLocal()
 mavenCentral()
 maven {
  url "http://jasperreports.sourceforge.net/maven2"
 }
 maven {
  url "http://jaspersoft.artifactoryonline.com/jaspersoft/third-party-ce-artifacts/"
 }
}

Creating new configuration


Before we write ant task to compile reports we have to create configuration.

1
2
3
4
configurations.create('jasperreports')
configurations.jasperreports {
 transitive = true
}

Adding dependency


Nothing new here. Just add new dependency to your project dependencies section.

1
2
3
dependencies {
 jasperreports 'net.sf.jasperreports:jasperreports:5.5.2'
}

Creating sourceSet


In new sourceSet we will be holding variables for ant task.

1
2
3
4
5
6
sourceSets {
 jasper {
  srcDir = file(relativePath('src/main/resources/reports'))
  classesDir = srcDir
 }
}

Ant task


We have to create ant task to compile *.jrxml files.

1
2
3
4
5
6
7
8
9
task compileJasperJava(overwrite: true) << {
 ant {
  taskdef(name: 'jrc', classname: 'net.sf.jasperreports.ant.JRAntCompileTask', classpath: configurations.jasperreports.asPath)
  sourceSets.jasper.classesDir.mkdirs()
  jrc(srcdir: sourceSets.jasper.srcDir, destdir: sourceSets.jasper.classesDir) {
   include(name:'**/*.jrxml')
  }
 }
}

Adding our task to compilation cycle


Just add following line to your build.gradle file:

1
classes.dependsOn compileJasperJava

Source


Gradle forum

Saturday, 31 May 2014

Writing custom permission evaluator in Spring

Lets say we have to implement permission engine in our application.

I will describe requirements during presentation of domain classes.

Model domain


Firstly. We have bunch of users.

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
@Entity
public class User {
    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false)
    private String login;

    @Column(nullable = false)
    private String password;

    @ManyToOne(targetEntity = UserRole.class, optional = false)
    @JoinColumn(name = "user_role")
    private UserRole userRole;
}

Each user has some standard attributes like login and password which are not important to us. What is important is user role. In most simplified solution user role can be either admin or "standard role".

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Role {
    @Id
    private String roleName;

    @ManyToMany
    @JoinTable(
        name = "role_permissions"
    )
    private Set<Permission> permissions;
}

@Entity
public class UserRole extends Role {
}

Each role comes with set of permissions. In example admin can block users, create new users, add news to home page etc.

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Entity
public class Permission {

    @Id
    private String permissionName;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Permission that = (Permission) o;

        if (!permissionName.equals(that.permissionName)) return false;

        return true;
    }

    @Override
    public int hashCode() {
        return 31 * permissionName.hashCode();
    }
}

These classes describes what user can and cannot do in our application. But this is not everything we have to check.

Users can be assigned to projects.

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@Entity
public class Project {
    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = true)
    private String description;
}

If user is assigned to project he plays some role in this project. User can be project manager, developer, client etc.

1
2
3
@Entity
public class ProjectRole extends Role {
}

To model this connection there is created additional entity.

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
@Entity
public class UserProjectRole {
    @Id
    @GeneratedValue
    private long id;

    @ManyToOne(optional = false)
    private User user;

    @ManyToOne(optional = false)
    private Project project;

    @ManyToOne(optional = false)
    private ProjectRole projectRole;
}

Working with this domain model we have to provide easy to use permission checker which handles two types of permissions: user permissions and project permissions.

Spring environment


Choosing Spring as our framework give us great possibilities. We are going to use following features:
  1. Data repositories
  2. Dependency injection
  3. Configuration components
  4. Expression-Based Access Control

Repositories


We have to create following repositories:
  1. PermissionRepository
  2. ProjectRepository
  3. RoleRepository
  4. UserRepository
  5. UserProjectRepository
All are similar to:

1
2
3
4
5
@Repository
public interface UserProjectRoleRepository extends CrudRepository<UserProjectRole, Long> {
    UserProjectRole findByUserAndProject(User user, Project project);
    List<UserProjectRole> findByUser(User user);
}

We also have to create UserService which will provide method to get currently logged user.

Basic permission checker


1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Component
public class PermissionChecker {
    private final UserService userService;
    private final UserProjectRoleRepository userProjectRoleRepository;

    @Autowired
    public PermissionChecker(UserService userService, UserProjectRoleRepository userProjectRoleRepository) {
        this.userService = userService;
        this.userProjectRoleRepository = userProjectRoleRepository;
    }

    public boolean hasProjectPermission(Project project, Permission permission) {
        User user = userService.getLoggedUser();
        UserProjectRole userProjectRole = userProjectRoleRepository.findByUserAndProject(user, project);

        if(userProjectRole != null) {
            return hasPermission(userProjectRole.getProjectRole().getPermissions(), permission);
        } else {
            return false;
        }
    }

    public boolean hasPermission(Permission permission) {
        User user = userService.getLoggedUser();
        return hasPermission(user.getUserRole().getPermissions(), permission);
    }

    private boolean hasPermission(Set<Permission> permissions, Permission permission) {
        return permissions
                .stream()
                .filter(setPermission -> setPermission.equals(permission))
                .findFirst().isPresent();
    }
}

This component has two public methods (except constructor). One for testing project permissions and one for testing user permissions.

In both methods we have to obtain permissions set and check if it contains our permission.

Annotation-based permission checking


We want to check our permissions in following way:

1
2
3
@PreAuthorize("hasPermission(#id, 'Project', 'project:delete') || hasPermission(#id, 'Project', 'project:everything')")
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_VALUE)
public void delete(@PathVariable("id") Long id) {}

Using PermissionChecker everywhere is redundant, time-consuming, error-prone and (most important) looks ugly.

How to achieve our goal?

Custom permission evaluator


Permission evaluator is class which handles invocations of hasPermission methods written inside @PreAuthorize annotation.

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class CustomPermissionEvaluator implements PermissionEvaluator {
    public static final String PROJECT_PERMISSION_TYPE = "Project";

    private final ProjectRepository projectRepository;
    private final PermissionChecker permissionChecker;

    @Autowired
    public CustomPermissionEvaluator(ProjectRepository projectRepository, PermissionChecker permissionChecker) {
        this.projectRepository = projectRepository;
        this.permissionChecker = permissionChecker;
    }

    @Override
    public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permissionText) {
        checkNotNull(permissionText);

        Permission permission = new Permission(permissionText.toString());

        if(targetDomainObject != null) {
            checkArgument(targetDomainObject instanceof Project, "Permissions are allowed only for Project objects");
            return permissionChecker.hasProjectPermission((Project) targetDomainObject, permission);
        }

        return permissionChecker.hasPermission(permission);
    }

    @Override
    public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permissionText) {
        checkArgument(targetType.equals(PROJECT_PERMISSION_TYPE), "Only project and user specific permission check is allowed");
        checkNotNull(permissionText);

        Project project = projectRepository.findOne(Long.parseLong(targetId.toString()));

        checkNotNull(project);

        Permission permission = new Permission();
        permission.setPermissionName(permissionText.toString());

        return permissionChecker.hasProjectPermission(project, permission);
    }
}

Each PermissionEvaluator  has to implement two hasPermission methods. It is required because we can invoke hasPermission (in @PreAuthorize) in many ways:

1
2
3
@PreAuthorize("hasPermission(#id, 'Project', 'project:delete')")
@PreAuthorize("hasPermission(#project, 'project:delete')")
@PreAuthorize("hasPermission(null, 'user:delete')")

Methods calls have different argument number.

First one check if user has permission to delete project and we are passing only project id.
Second one check if user has permission to delete project when we have project object.
Third one check if user has permission to delete user form database (we are basing here on user, not project, role).

Enabling our permission evaluator


After writing our own permission evaluator we have to enable it in our application. To do this we have to use @Configuration annotation.

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
    @Autowired
    private ProjectRepository projectRepository;

    @Autowired
    private PermissionChecker permissionChecker;

    public MethodSecurityConfig() {
    }

    @Autowired
    public MethodSecurityConfig(ProjectRepository projectRepository, PermissionChecker permissionChecker) {
        this.projectRepository = projectRepository;
        this.permissionChecker = permissionChecker;
    }

    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {
        CustomPermissionEvaluator permissionEvaluator = new CustomPermissionEvaluator(projectRepository, permissionChecker);

        DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
        expressionHandler.setPermissionEvaluator(permissionEvaluator);
        return expressionHandler;
    }
}

@EnableGlobalMethodSecurity(prePostEnabled = true) enables @PreAuthorize 
annotation.

Wednesday, 12 March 2014

Shiro JPA realm

This time code only.

1. Entity classes


You will also have to write simple DAOs for entity classes.

1.1 User


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package pl.dziurdziak.shiro.jpaRealm.user;

import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;

import pl.dziurdziak.shiro.jpaRealm.permission.Permission;
import pl.dziurdziak.shiro.jpaRealm.role.Role;

@Entity
@Table(name = "users")
public class User {

 @Id
 @GeneratedValue
 private long id;

 @NotNull
 private String login;

 @NotNull
 @Column(length = 64)
 private String password;

 @NotNull
 @Column(length = 80)
 private String salt;

 @ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
 private Set<Role> roles;

 @OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
 private Set<Permission> permissions;
 
 // getters and setters omitted
}

1.2 Role


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package pl.dziurdziak.easyReckoning.model.role;

import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.validation.constraints.Size;

import pl.dziurdziak.shiro.jpaRealm.user.User;

@Entity
@Table(name = "roles")
public class Role {

 @Id
 @GeneratedValue
 private long id;

 @Size(max = 100)
 private String roleName;

 @ManyToMany(mappedBy = "roles")
 private Set<User> users;

 // getters and setters ommitted
}


1.3 Permission



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package pl.dziurdziak.shiro.jpaRealm.permission;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.validation.constraints.Size;

import pl.dziurdziak.shiro.jpaRealm.User;

@Entity
@Table(name = "permissions")
public class Permission {

 @Id
 @GeneratedValue
 private long id;

 @Size(max = 100)
 private String permission;

 @ManyToOne()
 @JoinColumn(name = "USER_ID")
 private User user;

 // getters and setters omitted
}


2. Realm



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package pl.dziurdziak.shiro.jpaRealm.realm;

import java.util.HashSet;
import java.util.Set;

import javax.enterprise.inject.Default;
import javax.inject.Inject;

import org.apache.shiro.authc.AccountException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAccount;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.authz.permission.WildcardPermission;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import pl.dziurdziak.shiro.jpaRealm.permission.Permission;
import pl.dziurdziak.shiro.jpaRealm.role.Role;
import pl.dziurdziak.shiro.jpaRealm.user.User;
import pl.dziurdziak.shiro.jpaRealm.user.UserDao;

public class JpaAuthorizingRealm extends AuthorizingRealm {

 public static final String REALM_NAME = "MY_REALM";
 public static final int HASH_ITERATIONS = 200;

 @Inject
 private UserDao userDao;

 @Override
 protected AuthorizationInfo doGetAuthorizationInfo(final PrincipalCollection principals) {
  final String username = (String) principals.getPrimaryPrincipal();

  final User user = userDao.findByLogin(username);

  final Set<String> roles = new HashSet<>(user.getRoles().size());
  for (final Role role : user.getRoles()) {
   roles.add(role.getRoleName());
  }

  final Set<pl.dziurdziak.shiro.jpaRealm.permission.Permission> permissions = new HashSet<>(user.getPermissions().size());
  for (final Permission permission : user.getPermissions()) {
   permissions.add(new WildcardPermission(permission.getPermission()));
  }

  final SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(roles);
  authorizationInfo.setObjectPermissions(permissions);

  return authorizationInfo;
 }

 @Override
 protected AuthenticationInfo doGetAuthenticationInfo(final AuthenticationToken token) throws AuthenticationException {
  if (!(token instanceof UsernamePasswordToken)) {
   throw new IllegalStateException("Token has to be instance of UsernamePasswordToken class");
  }

  final UsernamePasswordToken userPassToken = (UsernamePasswordToken) token;

  if (userPassToken.getUsername() == null) {
   throw new AccountException("Null usernames are not allowed by this realm.");
  }

  final User user = userDao.findByLogin(userPassToken.getUsername());

  final SimpleAccount simpleAccount = new SimpleAccount(user.getLogin(), user.getPassword(), ByteSource.Util.bytes(user.getSalt()),
    REALM_NAME);

  return simpleAccount;
 }

 @Override
 @Inject
 public void setCredentialsMatcher(final CredentialsMatcher credentialsMatcher) {
  super.setCredentialsMatcher(credentialsMatcher);
 }

}

3. Utils class



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package pl.dziurdziak.shiro.jpaRealm;

import javax.enterprise.inject.Default;
import javax.enterprise.inject.Produces;

import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.apache.shiro.crypto.hash.SimpleHash;

import pl.dziurdziak.shiro.jpaRealm.realm.JpaAuthorizingRealm;

public final class JpaSecurityUtil {

 public static final int SALT_LENGTH = 80;
 public static final int PASSWORD_LENGTH = 64;

 public static String getSalt() {
  return new SecureRandomNumberGenerator().nextBytes(60).toBase64();
 }

 public static String hashPassword(final String value, final String salt) {
  final Sha256Hash sha256Hash = new Sha256Hash(value, salt, VaadinAuthorizingRealm.HASH_ITERATIONS);
  return sha256Hash.toHex();
 }

 @Produces
 @Default
 public CredentialsMatcher getCredentialMatcher() {
  final HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
  credentialsMatcher.setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME);
  credentialsMatcher.setHashIterations(JpaAuthorizingRealm.HASH_ITERATIONS);
  return credentialsMatcher;
 }

 @Produces
 @Default
 public SimpleHash getHash() {
  final Sha256Hash sha256Hash = new Sha256Hash();
  sha256Hash.setIterations(JpaAuthorizingRealm.HASH_ITERATIONS);
  return sha256Hash;
 }
}

4. Usage



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
package pl.dziurdziak.shiro.jpaRealm;

import pl.dziurdziak.shiro.jpaRealm.user.User;
import pl.dziurdziak.shiro.jpaRealm.user.UserDao;

public class TestClass {

 @Inject
 private UserDao userDao;

 public void register(final String login, final String password) {
  User user = new User();
  user.setLogin(login);
  user.setSalt(JpaSecurityUtil.getSalt());
  user.setPassword(JpaSecurityUtil.hashPassword(password, user.getSalt()));
  userDao.persist(user);
 }
}

Sunday, 17 November 2013

How to extract information from html

People like to say that we live in global village. Internet access gave us many possibilities but everything comes with the price.

Informations in the Internet are not well-organised. Typical webmaster focuses on how data is presented not how are they stored. Web pages are not easy to parse. Hardly ever we find extracting informations from them to be an easy task.

Sure... More and more websites is offering some kind of public API which allows easier development but it is only drop in the ocean. Usually we are forced to work with raw html.

Html is not an easy language to work with. Unlike xml, html pages does not have to follow strict syntax (in example not all tags have to be closed). Thus we cannot use xQuery (which is extremely powerful).

So how we can extract data from html?


Luckily there is a way.

Some good souls have created library called jsoup. It is "Java library for working with real-world HTML".

I will introduce it through example.

Lets say I want to show to my user informations about one of the best films of all times. In order to this I have to connect with some website about movies and get data from it.

I will use fallowing page:
http://www.allmovie.com/movie/the-good-the-bad-and-the-ugly-v20333

1. Prerequisites


Firstly add jsoup library to your project. You can do this using maven dependency:

1
2
3
4
5
<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>1.7.2</version>
</dependency>

2. Parsing web page

 

In order to extract data we have to parse web page. It is ridiculously easy with jsoup:

1
Document doc = Jsoup.connect("http://www.allmovie.com/movie/the-good-the-bad-and-the-ugly-v20333").get();

And that is all. Library will do all necessary work: connecting, downloading and parsing. After that we are able to process document.

3. Extracting informations

 

To extract information we have to analyse html document. We have to understand its hierarchy to prepare query (yes - we are using queries to select elements).

Most interesting film informations are placed inside div tag which class attribute is equal to "side-details". In this elements we have dt tags (descriptions) immediately followed by dd tags which contains data we are searching for.

Basically it looks like this:

1
2
3
4
5
6
7
8
<div class="side-details">   
    <dt>genres</dt>
    <dd>
        <ul class="warning-list">
            <li><a href="http://www.allmovie.com/genre/western-d656">Western</a></li>
        </ul>
    </dd>
</div>

Here is how we can get film genre:

1
2
Element element = doc.select("* div[class=side-details] dt:contains(genres) + dd").first();
String genre = element.text();

Selectors are described at jquery official website. I encourage you to read it.

* means we are selecting all elements (at root level). Next we have space and another selector. Space has special importance - it means that second selector (div[class=side-details]) will be used to evaluate all descendants (at any level in hierarchy). div[class=side-details] will choose all div elements whose have class attribute equals to "side-details". In descendants of div element (remember about space) we are searching for dt element containing text "genres". Now we are using + operator - it is used to select all following siblings. From siblings we are selecting only dd elements and then using java function we are getting first of them.

Done. Using only one short line we were able to get useful information from real-word website.

Monday, 12 August 2013

Enums and interfaces? Interesting connection

We often have to make a decision based on enum value. Usually it ends in long switch statement. What if I told you there is a better way to do this?

1. What do we want?


We want our enum to be self-describing and to achive this we created interface:

1
2
3
public interface SelfDescribing {
 String getDescription();
}


2. What do we have?


1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public enum MessageType implements SelfDescribing {
 INFO, WARNING, ERROR;

 public String getDescription() {
  switch (this) {
  case ERROR:
   return "What do you want? Go fix your problem.";
  case INFO:
   return "Hi i'm INFO Message";
  case WARNING:
   return "Hi i'm WARNING Message";
  default:
   return null;
  }
 }
}


What we see here is switch statement. It's just ugly and after you add new message type you will have to remember about extending it. Compiler won't remind you about it.

3. What is more elegant solution?


1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
public enum MessageType implements SelfDescribing{
 INFO
 {
  public String getDescription() {
   return "Hi i'm INFO Message";
  }
  
 }, WARNING
 {
  public String getDescription() {
   return "Hi i'm WARNING Message";
  }
 }, ERROR
 {
  public String getDescription() {
   return "What do you want? Go fix your problem.";
  }
 };
}


It's cleaner, more focused on goal and less error-prone.