001package org.tynamo.security.shiro;
002
003import java.io.ByteArrayInputStream;
004import java.io.ByteArrayOutputStream;
005import java.io.IOException;
006import java.io.ObjectInputStream;
007import java.io.ObjectOutputStream;
008import java.util.Collection;
009import java.util.zip.GZIPInputStream;
010import java.util.zip.GZIPOutputStream;
011
012import org.apache.shiro.io.SerializationException;
013import org.apache.shiro.io.Serializer;
014import org.apache.shiro.subject.PrincipalCollection;
015import org.apache.shiro.subject.SimplePrincipalCollection;
016
017/**
018 * Creates A GZIPed rememberMe cookie, based on the patch for SHIRO-226 (https://issues.apache.org/jira/browse/SHIRO-226)
019 */
020
021public class SimplePrincipalSerializer implements Serializer<PrincipalCollection> {
022        /**
023         * Magic number to signal that this is a SimplePrincipalSerializer file so that we don't try to decode something crap.
024         */
025        private static final int MAGIC = 0x0BADBEEF;
026
027        public byte[] serialize(PrincipalCollection pc) throws SerializationException {
028                ByteArrayOutputStream ba = new ByteArrayOutputStream();
029
030                try {
031                        GZIPOutputStream gout = new GZIPOutputStream(ba);
032                        ObjectOutputStream out = new ObjectOutputStream(gout);
033
034                        // Write the magic number which allows us to decode it later on
035                        out.writeInt(MAGIC);
036
037                        // Limited to 32768 realms. Should be enough for everybody.
038                        out.writeShort(pc.getRealmNames().size());
039
040                        for (String realm : pc.getRealmNames()) {
041                                out.writeUTF(realm);
042
043                                Collection<?> principals = pc.fromRealm(realm);
044
045                                // Again, limited to 32768 principals.
046                                out.writeShort(principals.size());
047
048                                for (Object principal : principals) {
049                                        out.writeObject(principal);
050                                }
051                        }
052                        gout.finish();
053                } catch (IOException e) {
054                        throw new SerializationException(e.getMessage());
055                }
056                return ba.toByteArray();
057        }
058
059        public PrincipalCollection deserialize(byte[] serialized) throws SerializationException {
060                ByteArrayInputStream ba = new ByteArrayInputStream(serialized);
061
062                try {
063                        GZIPInputStream gin = new GZIPInputStream(ba);
064                        ObjectInputStream in = new ObjectInputStream(gin);
065                        SimplePrincipalCollection pc = new SimplePrincipalCollection();
066
067                        // Check magic number
068                        if (in.readInt() != MAGIC)
069                                throw new SerializationException(
070                                        "Not valid magic number while deserializing stored PrincipalCollection - possibly obsolete cookie.");
071
072                        int numRealms = in.readShort();
073
074                        // realms loop
075                        for (int i = 0; i < numRealms; i++) {
076                                String realmName = in.readUTF();
077
078                                int numPrincipals = in.readShort();
079
080                                // principals loop
081                                for (int j = 0; j < numPrincipals; j++) {
082                                        Object principal = in.readObject();
083
084                                        pc.add(principal, realmName);
085                                }
086                        }
087
088                        return pc;
089                } catch (IOException e) {
090                        throw new SerializationException(e.getMessage());
091                } catch (ClassNotFoundException e) {
092                        throw new SerializationException(e.getMessage());
093                }
094        }
095}