View Javadoc
1   package org.oxerr.jackson.module.jsr250;
2   
3   import java.io.IOException;
4   import java.io.ObjectInputStream;
5   import java.util.Collection;
6   import java.util.Collections;
7   
8   import javax.annotation.security.DenyAll;
9   import javax.annotation.security.RolesAllowed;
10  
11  import org.apache.logging.log4j.LogManager;
12  import org.apache.logging.log4j.Logger;
13  import org.springframework.security.core.Authentication;
14  import org.springframework.security.core.GrantedAuthority;
15  import org.springframework.security.core.context.SecurityContextHolder;
16  
17  import com.fasterxml.jackson.core.JsonGenerationException;
18  import com.fasterxml.jackson.core.JsonGenerator;
19  import com.fasterxml.jackson.databind.JsonMappingException;
20  import com.fasterxml.jackson.databind.SerializerProvider;
21  import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
22  import com.fasterxml.jackson.databind.ser.BeanSerializer;
23  
24  /**
25   * Excludes the properties that are {@link DenyAll} or not {@link RolesAllowed}
26   * from the serialization output.
27   */
28  public class Jsr250JsonSerializer extends BeanSerializer {
29  
30  	private static final long serialVersionUID = 2016100501L;
31  
32  	private transient Logger log = LogManager.getLogger(Jsr250JsonSerializer.class);
33  
34  	public Jsr250JsonSerializer(BeanSerializer serializer) {
35  		super(serializer);
36  	}
37  
38  	/**
39  	 * {@inheritDoc}
40  	 */
41  	@Override
42  	protected void serializeFields(Object bean, JsonGenerator gen, SerializerProvider provider)
43  					throws IOException, JsonGenerationException {
44  		final Collection<? extends GrantedAuthority> grantedAuthorities = this
45  				.getGrantedAuthorities();
46  
47  		final BeanPropertyWriter[] props;
48  		if (_filteredProps != null && provider.getActiveView() != null) {
49  			props = _filteredProps;
50  		} else {
51  			props = _props;
52  		}
53  		int i = 0;
54  		try {
55  			for (final int len = props.length; i < len; ++i) {
56  				BeanPropertyWriter prop = props[i];
57  				if (prop != null) { // can have nulls in filtered list
58  					final DenyAll denyAll = prop.getAnnotation(DenyAll.class);
59  					final RolesAllowed rolesAllowed = prop.getAnnotation(RolesAllowed.class);
60  					if (denyAll != null) {
61  						log.trace("DenyAll, ignoring {}.", prop);
62  					} else if (rolesAllowed != null && !this.isAllowed(rolesAllowed.value(), grantedAuthorities)) {
63  						log.trace("RolesAllowed({}), ignoring {}.", rolesAllowed::value, () -> prop);
64  					} else {
65  						prop.serializeAsField(bean, gen, provider);
66  					}
67  				}
68  			}
69  			if (_anyGetterWriter != null) {
70  				_anyGetterWriter.getAndSerialize(bean, gen, provider);
71  			}
72  		} catch (Exception e) {
73  			String name = (i == props.length) ? "[anySetter]" : props[i].getName();
74  			wrapAndThrow(provider, e, bean, name);
75  		} catch (StackOverflowError e) {
76  			/* 04-Sep-2009, tatu: Dealing with this is tricky, since we do not
77  			 *   have many stack frames to spare... just one or two; can't
78  			 *   make many calls.
79  			 */
80  			// 10-Dec-2015, tatu: and due to above, avoid "from" method, call ctor directly:
81  			//JsonMappingException mapE = JsonMappingException.from(gen, "Infinite recursion (StackOverflowError)", e);
82  			JsonMappingException mapE = new JsonMappingException("Infinite recursion (StackOverflowError)", e);
83  
84  			String name = (i == props.length) ? "[anySetter]" : props[i].getName();
85  			mapE.prependPath(new JsonMappingException.Reference(bean, name));
86  			throw mapE;
87  		}
88  	}
89  
90  	protected boolean isAllowed(String[] rolesAllowed, Collection<? extends GrantedAuthority> grantedAuthorities) {
91  		for (final String role : rolesAllowed) {
92  			for (final GrantedAuthority grantedAuthority : grantedAuthorities) {
93  				if (role.equals(grantedAuthority.getAuthority())) {
94  					return true;
95  				}
96  			}
97  		}
98  		return false;
99  	}
100 
101 	protected Collection<? extends GrantedAuthority> getGrantedAuthorities() {
102 		final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
103 		return authentication != null ? authentication.getAuthorities() : Collections.emptyList();
104 	}
105 
106 	private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
107 		this.log = LogManager.getLogger(Jsr250JsonSerializer.class);
108 	}
109 
110 }