spring-projects / spring-security

Spring Security
http://spring.io/projects/spring-security
Apache License 2.0
8.74k stars 5.87k forks source link

SEC-3072: Provide Freemarker macro library #3275

Open spring-projects-issues opened 9 years ago

spring-projects-issues commented 9 years ago

Angel D. Segarra (Migrated from SEC-3072) said:

Spring Framework Web MVC currently ships Freemarker and Velocity macro libraries along with the JSP taglib , but Spring security ships only a JSP taglib which leaves users of the other technologies without good options out of the box. To make matters worse JspTaglibs hash in Freemarker no longer works in Spring Boot. I am requesting support parity with at least Freemarker to match Spring Web MVC.

rob-baily commented 7 years ago

I've come up with a starting macro for this type of library below. @rwinch if we wanted to submit a pull request to start this could you give us some guidance on where it might be appropriate to live within the Spring Security ecosystem?

<#macro authorize ifAnyGranted> <#assign authorized = false> <#list Session["SPRING_SECURITY_CONTEXT"].authentication.authorities as authority> <#if authority == ifAnyGranted> <#assign authorized = true> </#if> </#list> <#if authorized> <#nested> </#if> </#macro>

rwinch commented 7 years ago

Thanks!

I honestly think the first step is to ensure that this support is migrated to use objects that are populated on the request attributes. Then libraries can leverage those objects to ensure they get consistent results. View technologies that are fairly flexible could even just use the objects directly without needing a specific DSL this way.

rob-baily commented 7 years ago

@rwinch So the only reference I could find on how to get access to the Spring security information is here which mentions session but not request objects. Is there a better place to find out where they would be in the request and how to access them? Any example code that can be reviewed?

rob-baily commented 7 years ago

@rwinch I was wondering if you or anyone else could give some clues on how to do what you have mentioned here? As I said I could not find any good reference on where the request attributes that hold objects are.

hellomynameistj commented 7 years ago

I found that SPRING_SECURITY_CONTEXT was at the top level and was only available if somebody was logged in so I have altered @rob-baily 's script and is working for me. Hopefully might help somebody.

<#macro requiredRole Role> <#assign authorized = false> <#if SPRING_SECURITY_CONTEXT??> <#list SPRING_SECURITY_CONTEXT.authentication.authorities as authority> <#if authority == Role> <#assign authorized = true> </#if> </#list> </#if> <#if authorized> <#nested> </#if> </#macro>

DuncanCasteleyn commented 5 years ago

<#macro authorize ifAnyGranted> <#assign authorized = false> <#list Session["SPRING_SECURITY_CONTEXT"].authentication.authorities as authority> <#if authority == ifAnyGranted> <#assign authorized = true> </#if> </#list> <#if authorized> <#nested> </#if> </#macro>

This macro helped allot, thanks.

doctore commented 5 months ago

I had this problem upgrading an old project from Spring 3 to Spring 6, by now we have no time to replace the technology used to render the views, so my solution for JSP security tags was rewrite them using FreeMarker macros:

<#ftl output_format="HTML" strip_whitespace=true> 
<#-- 
 * security.ftl 
 * 
 * This file consists of a collection of FreeMarker macros aimed at easing 
 * some of the common requirements of web applications - in particular 
 * handling of security. 
--> 

<#-- 
 * isAnonymous 
 * 
 * Verifies if there is no a logged user.
--> 
<#macro isAnonymous> 
  <#assign anonymous = true> 
  <#if SPRING_SECURITY_CONTEXT??> 
    <#assign anonymous = false> 
  </#if> 
  <#if anonymous> 
    <#nested> 
  </#if> 
</#macro> 

<#-- 
 * isAuthenticated 
 * 
 * Checks if there is a logged user and he/she is authenticated. 
--> 
<#macro isAuthenticated> 
  <#assign authenticated = false> 
  <#if SPRING_SECURITY_CONTEXT??> 
    <#assign authentication = SPRING_SECURITY_CONTEXT.authentication
              isUserAuthenticated = authentication.isAuthenticated()> 
    <#if isUserAuthenticated> 
      <#assign authenticated = true> 
    </#if> 
  </#if> 
  <#if authenticated> 
    <#nested> 
  </#if> 
</#macro>

<#-- 
 * hasRole 
 * 
 * Verifies if there is a logged user and he/she has the given role/authority.
 * 
 * Example: 
 * 
 *   <@security.hasRole role="ROLE_ADMIN"> 
 *     <br><span>User has the role: ROLE_ADMIN</span> 
 *   </@security.hasRole> 
 * 
 * @param role 
 *    The role and/or authority to verify 
--> 
<#macro hasRole role> 
  <#assign authorized = false> 
  <#if SPRING_SECURITY_CONTEXT?? && role??> 
    <#list SPRING_SECURITY_CONTEXT.authentication.authorities as authority> 
      <#if authority == role> 
        <#assign authorized = true> 
      </#if> 
    </#list> 
  </#if> 
  <#if authorized> 
    <#nested> 
  </#if> 
</#macro>

<#-- 
 * ifAnyGranted 
 * 
 * Checks if there is a logged user and he/she has one of the given roles/authorities. 
 * 
 * Example: 
 * 
 *   <@security.ifAnyGranted roles="ROLE_ADMIN,ROLE_SUPERADMIN"> 
 *     <br><span>User has one of the roles: ROLE_ADMIN, ROLE_SUPERADMIN</span> 
 *   </@security.ifAnyGranted> 
 * 
 * @param roles 
 *    Roles and/or authorities separated by commas to verify 
--> 
<#macro ifAnyGranted roles> 
  <#assign authorized = false> 
  <#if SPRING_SECURITY_CONTEXT?? && roles??> 
    <#list SPRING_SECURITY_CONTEXT.authentication.authorities as authority> 
      <#list roles?split(",") as role> 
        <#if authority == role> 
          <#assign authorized = true> 
        </#if> 
      </#list> 
    </#list> 
  </#if> 
  <#if authorized> 
    <#nested> 
  </#if> 
</#macro>

<#--
 * ifNotGranted
 *
 * Checks if there is a logged user and he/she does not have any of the given roles/authorities.
 *
 * Example:
 *
 *   <@security.ifNotGranted roles="ROLE_ADMIN,ROLE_SUPERADMIN">
 *      <br><span>User does not have any of the roles: ROLE_ADMIN, ROLE_SUPERADMIN</span>
 *   </@security.ifNotGranted>
 *
 * @param roles
 *    Roles and/or authorities separated by commas to verify
 -->
<#macro ifNotGranted roles>
    <#assign authorized = false>
    <#if SPRING_SECURITY_CONTEXT?? && roles??>
        <#assign authorized = true>
        <#list SPRING_SECURITY_CONTEXT.authentication.authorities as authority>
            <#list roles?split(",") as role>
                <#if authority == role>
                    <#assign authorized = false>
                </#if>
            </#list>
        </#list>
    </#if>
    <#if authorized>
        <#nested>
    </#if>
</#macro>

I added it to the file security.ftl and import it in a common ftl file using:

<#import "security.ftl" as security />