001    /*
002     * Copyright (C) 2014 XStream Committers.
003     * All rights reserved.
004     *
005     * Created on 08. January 2014 by Joerg Schaible
006     */
007    package com.thoughtworks.xstream.mapper;
008    
009    import java.util.ArrayList;
010    import java.util.Arrays;
011    import java.util.List;
012    
013    import com.thoughtworks.xstream.security.AnyTypePermission;
014    import com.thoughtworks.xstream.security.ForbiddenClassException;
015    import com.thoughtworks.xstream.security.NoTypePermission;
016    import com.thoughtworks.xstream.security.TypePermission;
017    
018    
019    /**
020     * A Mapper implementation injecting a security layer based on permission rules for any type required in the
021     * unmarshalling process.
022     * 
023     * @author Jörg Schaible
024     * @since 1.4.7
025     */
026    public class SecurityMapper extends MapperWrapper {
027    
028        private final List permissions;
029    
030        /**
031         * Construct a SecurityMapper.
032         * 
033         * @param wrapped the mapper chain
034         * @since 1.4.7
035         */
036        public SecurityMapper(final Mapper wrapped) {
037            this(wrapped, (TypePermission[])null);
038        }
039    
040        /**
041         * Construct a SecurityMapper.
042         * 
043         * @param wrapped the mapper chain
044         * @param permissions the predefined permissions
045         * @since 1.4.7
046         */
047        public SecurityMapper(final Mapper wrapped, final TypePermission[] permissions) {
048            super(wrapped);
049            this.permissions = permissions == null //
050                ? new ArrayList()
051                : new ArrayList(Arrays.asList(permissions));
052        }
053    
054        /**
055         * Add a new permission.
056         * <p>
057         * Permissions are evaluated in the added sequence. An instance of {@link NoTypePermission} or
058         * {@link AnyTypePermission} will implicitly wipe any existing permission.
059         * </p>
060         * 
061         * @param permission the permission to add.
062         * @since 1.4.7
063         */
064        public void addPermission(final TypePermission permission) {
065            if (permission.equals(NoTypePermission.NONE) || permission.equals(AnyTypePermission.ANY))
066                permissions.clear();
067            permissions.add(0, permission);
068        }
069    
070        public Class realClass(final String elementName) {
071            final Class type = super.realClass(elementName);
072            for (int i = 0; i < permissions.size(); ++i) {
073                final TypePermission permission = (TypePermission)permissions.get(i);
074                if (permission.allows(type))
075                    return type;
076            }
077            throw new ForbiddenClassException(type);
078        }
079    }