I am using AccessReferenceMap from OWASP to secure my ids in URLs. The problem is that when list of IDs to be obfuscated is related to particular customer. Here is my configuration:
<bean id="hyperlinkMapping" class="web.security.HyperlinkMapping" scope="session">
<aop:scoped-proxy />
</bean>
<bean id="tracksAccessMap" class="web.security.EntityAccessMap"
scope="session" factory-method="create">
<constructor-arg index="0" ref="allTrackIdsForCustomer" />
<aop:scoped-proxy/>
</bean>
<bean id="allTrackIdsForCustomer" scope="session"
factory-bean="webTrackDAO"
factory-method="findAllTrackIdsForCustomer">
<aop:scoped-proxy/>
</bean>
<bean id="webTrackDAO" class="web.repository.impl.WebTrackDAOImpl"/>
EntityAccessMap:
package web.security;
import java.util.Iterator;
import java.util.List;
import org.apache.log4j.Logger;
import org.owasp.esapi.AccessReferenceMap;
import org.owasp.esapi.errors.AccessControlException;
import org.owasp.esapi.reference.RandomAccessReferenceMap;
import org.springframework.stereotype.Component;
import core.domain.Entity;
@Component
public class EntityAccessMap<T extends Entity> implements AccessMap<T> {
private static Logger logger = Logger.getLogger(EntityAccessMap.class);
private static final long serialVersionUID = -436098952674898327L;
private AccessReferenceMap<String> map = new RandomAccessReferenceMap();
public EntityAccessMap() {
}
private EntityAccessMap(final List<T> entities) {
logger.info("Entities size: " + entities.size());
for (final T entity : entities) {
map.addDirectReference(entity);
}
}
public <T extends Entity> AccessMap<T> create(final List<T> entities) {
logger.info("calling create with entities' size " + entities.size() );
return new EntityAccessMap<>(entities);
}
public String getIndirectReference(final T entity) {
for( Iterator it = map.iterator(); it.hasNext(); ) {
logger.info((String)it.next().toString());
}
logger.info("Entity: " + map.getIndirectReference(entity));
return map.getIndirectReference(entity);
}
public T getDirectReference(final String indirectReference) {
try {
return map.getDirectReference(indirectReference);
} catch (AccessControlException e) {
throw new IllegalArgumentException("Indirect Reference is not valid", e);
}
}
}
AccessMap:
package web.security;
import java.io.Serializable;
import core.domain.Entity;
public interface AccessMap<T extends Entity> extends Serializable {
String getIndirectReference(final T entity);
T getDirectReference(final String indirectReference);
}
HyperlinkMapping:
package web.security;
import java.io.Serializable;
import org.springframework.beans.factory.annotation.Autowired;
import core.domain.track.Track;
public class HyperlinkMapping implements Serializable {
private static final long serialVersionUID = -2011016815710653498L;
@Autowired AccessMap<Track> tracksAccessMap;
public String getTrackId(final Track track) {
return tracksAccessMap.getIndirectReference(track);
}
public Track getTrack(final String indirectId) {
return tracksAccessMap.getDirectReference(indirectId);
}
}
So, what I want to achieve: tracksAccessMap should be filled only with customer's related ids, not whole set. How to initialize all these beans after customer's login (and setting customerId session attribute)?
EDIT 1: additional code:
TracksController:
package web.controller;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import core.constants.WebConstants;
import web.service.TrackService;
@Controller
@Secured("ROLE_USER")
@RequestMapping(WebConstants.WEB_MY)
@Scope("session")
public class TracksController {
@Autowired
private TrackService trackService;
@Autowired
private HyperlinkMapping hyperlinkMapping;
@RequestMapping(value=WebConstants.WEB_MYTRACKS, method = RequestMethod.GET, produces = "application/json")
public ModelAndView showTracks( HttpServletRequest request, @RequestParam(value = "pageSize", required = false) Integer pageSize ) {
ModelAndView mv = new ModelAndView();
mv.addObject("pagedListHolder",trackService.getTracksList(request, pageSize == null ? 10 : pageSize ));
mv.addObject("hyperlinkMapping",hyperlinkMapping);
return mv;
}
}
centerColTracks.jsp
<c:forEach items="${pagedListHolder.pageList}" var="item">
<tr>
<td>${item.id}</td>
<td style="color:blue;text-align:right"><a href="<c:url value="${request.getRequestURL()}/my/tracks/${hyperlinkMapping.getTrackId(item)}"/>">${item.name}</a></td>
<td style="color:blue;text-align:right">${item.trackDate}</td>
<td style="color:blue;text-align:right">${item.description}</td>
</tr>
</c:forEach>
hyperlinkMapping.getTrackId(item) should return ONLY trackId (taken from AccessReferenceMap) related ONLY for customer logged in. In other words - hyperlinkMapping should be instantiated right after the login.
I have two ideas how to do this: 1. AOP with after-returning advice, or 2. use SimpleUrlAuthenticationSuccessHandler, where I can instantiate HyperlinkMapping after login. Or I can use it with the current implementation and I just simply forgot something?