001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.runtime.security;
020
021import java.io.IOException;
022import java.util.Set;
023
024import lucee.commons.digest.MD5;
025import lucee.commons.io.IOUtil;
026import lucee.commons.io.res.Resource;
027import lucee.runtime.coder.Base64Coder;
028import lucee.runtime.exp.ApplicationException;
029import lucee.runtime.exp.PageException;
030import lucee.runtime.op.Caster;
031import lucee.runtime.type.Array;
032import lucee.runtime.type.util.ListUtil;
033
034/**
035 * User Password Information
036 */
037public final class CredentialImpl implements Credential {
038    String username;
039    String password;
040    String[] roles;
041        private Resource rolesDir;
042    private static final char ONE=(char)1;
043
044    /**
045     * credential constructor
046     * @param username
047     */
048    public CredentialImpl(String username,Resource rolesDir) {
049        this(username,null,new String[0],rolesDir);
050    }
051    
052    /**
053     * credential constructor
054     * @param username
055     * @param password
056     */
057    public CredentialImpl(String username,String password,Resource rolesDir) {
058        this(username,password,new String[0],rolesDir);
059    }
060    
061    /**
062     * credential constructor
063     * @param username
064     * @param password
065     * @param roles
066     * @throws PageException
067     */
068    public CredentialImpl(String username,String password, String roles,Resource rolesDir) throws PageException {
069        this(username,password,toRole(roles),rolesDir);
070    }
071    
072    /**
073     * credential constructor
074     * @param username
075     * @param password
076     * @param roles
077     * @throws PageException
078     */
079    public CredentialImpl(String username,String password, Array roles,Resource rolesDir) throws PageException {
080        this(username,password,toRole(roles),rolesDir);
081    }
082    
083    /**
084     * credential constructor
085     * @param username
086     * @param password
087     * @param roles
088     */
089    public CredentialImpl(String username,String password,String[] roles,Resource rolesDir) {
090        this.username=username;
091        this.password=password;
092        this.roles=roles;
093        this.rolesDir=rolesDir;
094    }
095
096    @Override
097    public String getPassword() {
098        return password;
099    }
100    @Override
101    public String[] getRoles() {
102        return roles;
103    }
104    @Override
105    public String getUsername() {
106        return username;
107    }
108    
109    /**
110     * convert a Object to a String Array of Roles
111     * @param oRoles
112     * @return roles
113     * @throws PageException
114     */
115    public static String[] toRole(Object oRoles) throws PageException {
116        if(oRoles instanceof String) {
117            oRoles=ListUtil.listToArrayRemoveEmpty(oRoles.toString(),",");
118        }
119        
120        if(oRoles instanceof Array) {
121            Array arrRoles = (Array) oRoles;
122            String[] roles=new String[arrRoles.size()];
123            for(int i=0;i<roles.length;i++) {
124                roles[i]=Caster.toString(arrRoles.get(i+1,""));
125            }
126            return roles;
127        }
128        throw new ApplicationException("invalid roles definition for tag loginuser");
129    }
130
131    public String serialize() {
132        return serialize(null);
133    }
134
135    public String serialize(Set<Object> done) {
136        return "createObject('java','lucee.runtime.security.Credential').init('"+username+"','"+password+"','"+ListUtil.arrayToList(roles,",")+"')";
137    } 
138    
139    
140    @Override
141    public String encode() throws PageException{
142        String raw=ListUtil.arrayToList(roles,",");
143                if(raw.length()>100){
144                try {
145                        if(!rolesDir.exists())rolesDir.mkdirs();
146                        String md5 = MD5.getDigestAsString(raw);
147                                IOUtil.write(rolesDir.getRealResource(md5), raw, "utf-8", false);
148                                return Caster.toB64(username+ONE+password+ONE+"md5:"+md5,"UTF-8");
149                        } 
150                catch (IOException e) {}
151                }
152        try {
153                        return Caster.toB64(username+ONE+password+ONE+raw,"UTF-8");
154                } catch (Exception e) {
155                        throw Caster.toPageException(e);
156                }
157    } 
158    
159    /**
160     * decode the Credential form a Base64 String value
161     * @param encoded
162     * @return Credential from decoded string
163     * @throws PageException
164     */
165    public static Credential decode(Object encoded,Resource rolesDir) throws PageException {
166        String dec;
167        try {
168                        dec=Base64Coder.decodeToString(Caster.toString(encoded),"UTF-8");
169                } catch (Exception e) {
170                        throw Caster.toPageException(e);
171                }
172        
173        Array arr=ListUtil.listToArray(dec,""+ONE);
174        int len=arr.size();
175        if(len==3) {
176                String str=Caster.toString(arr.get(3,""));
177                if(str.startsWith("md5:")){
178                        if(!rolesDir.exists())rolesDir.mkdirs();
179                        str=str.substring(4);
180                        Resource md5 = rolesDir.getRealResource(str);
181                        try {
182                                        str=IOUtil.toString(md5, "utf-8");
183                                } catch (IOException e) {
184                                        str="";
185                                }
186                }
187                
188                return new CredentialImpl(Caster.toString(arr.get(1,"")),Caster.toString(arr.get(2,"")),str,rolesDir);
189        }
190        if(len==2) return new CredentialImpl(Caster.toString(arr.get(1,"")),Caster.toString(arr.get(2,"")),rolesDir);
191        if(len==1) return new CredentialImpl(Caster.toString(arr.get(1,"")),rolesDir);
192        
193        return null;
194    }
195
196        @Override
197        public String toString() {
198                return "username:"+username+";password:"+password+";roles:"+roles;
199        } 
200    
201}