Skip to main content

Spring Security part 5 - Freemarker Security Tags

 In this series of Spring Security articles, I’ve walked you through the configuration, authentication and authorization cycles. In this final article, I’m going to show you how to set up security tags in Free Marker. The concepts I’m going to show you work equally well in JSP, Thymeleaf and Tiles.

Other Articles

If you’re new to Spring, you should take a look at Getting started with Spring Framework for Web Apps

1 Security Tags

Implementing security tags with server-side rendering technologies is fairly common, but Spring Security doesn’t ship with any out of the box. Thankfully, setting these up in Free Marker (and others) is fairly straight-forward. This article will leverage knowledge and code exposed in prior articles so it would be a good idea to review those first.

1.2 Creating the tags

The code I’m using has been adapted from https://github.com/jagregory/shiro-freemarker-tags for Freemarker running with Spring Security. After copying these classes into my project, I modified them to work with Spring Security, GrantedAuthority and my user contexts.

The SecurityTags class is the entry point from your FreeMarker template. The names you give your tags here is how you’ll use it in your template.

public class SecurityTags extends SimpleHash {
    public SecurityTags() {
        put("authenticated", new AuthenticatedTag());
    	
        put("guest", new GuestTag());
        put("hasAnyRole", new HasAnyRolesTag());
        put("hasPermission", new HasPermissionTag());
        put("hasRole", new HasRoleTag());
        put("lacksPermission", new LacksPermissionTag());
        put("lacksRole", new LacksRoleTag());
        put("notAuthenticated", new NotAuthenticatedTag());
        put("principal", new PrincipalTag());
        put("user", new UserTag());
        
    }
}

1.3 Customizing your tags

The PermissionTag is a good example to see a custom SecurityUtils in action.

public abstract class PermissionTag extends SecureTag {
    String getName(Map params) {
        return getParam(params, "name");
    }
    
    @Override
    protected void verifyParameters(Map params) throws TemplateModelException {
        String permission = getName(params);

        if (permission == null || permission.length() == 0) {
            throw new TemplateModelException("The 'name' tag attribute must be set.");
        }
    }

    @Override
    public void render(Environment env, Map params, TemplateDirectiveBody body) throws IOException, TemplateException {
        String p = getName(params);

        boolean show = showTagBody(p);
        if (show) {
            renderBody(env, body);
        }
    }

    protected boolean isPermitted(String p) {
    	UserContext userContext = SecurityUtils.getUserContext();
    	
    	if (userContext != null) {
    		return userContext.hasAnyRole(p);
    	}
    	return false;
    }

    protected abstract boolean showTagBody(String p);
}

2 FreeMarkerConfigurer

Finally, you’ll want to create a new bean in your Configuration that returns a FreeMarkerConfigurer. Add in a shared variable called security and set the object to a new SecurityTags object.

    @Bean
    public FreeMarkerConfigurer freeMarkerConfigurer() throws IOException {
    	FreeMarkerConfigurer freeMarkerConfigurer = new FreeMarkerConfigurer();

    	// Create a new configuration 
    	freemarker.template.Configuration config = new freemarker.template.Configuration(freemarker.template.Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
    	
    	// Set the templateLoader based on the ClassTemplateLoader
    	config.setTemplateLoader( new ClassTemplateLoader(getClass(), "/templates"));
    	
    	// Set up tags to assist with security in the templates
    	config.setSharedVariable("security", new SecurityTags());

    	// Set the configuration and return the configurer
    	freeMarkerConfigurer.setConfiguration(config);
    	
    	return freeMarkerConfigurer;
    }

2.1 Using the security tags

Now, in your FreeMarker template file you can use the security tags by using <@ TAGNAME>.

<@security.authenticated>
	<p>IS AUTHENTICATED</p>
</@security.authenticated>

<@security.hasRole name="USER">
	<h3>You have the USER role</h3>
</@security.hasRole>

<@security.hasAnyRole name="ADMIN,WEBMASTER">
	<h3>Has at least one of these roles: ADMIN,WEBMASTER</h3>
</@security.hasAnyRole>

Comments

Popular posts from this blog

Max Upload File Size in Spring Framework

Use Java Enums with JPA

Spring Security part 3 - OidcUser