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}