/* ======================================================= Copyright 2014 - ePortfolium - Licensed under the Educational Community License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.osedu.org/licenses/ECL-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ======================================================= */ package com.portfolio.data.attachment; import java.io.BufferedWriter; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.net.Inet4Address; import java.net.InetAddress; import java.net.NetworkInterface; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Enumeration; import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.SecretKeySpec; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.portfolio.data.provider.DataProvider; import com.portfolio.data.utils.ConfigUtils; import com.portfolio.data.utils.LogUtils; import com.portfolio.data.utils.SqlUtils; import com.portfolio.security.Credential; public class DirectURLService extends HttpServlet { /** * */ final Logger logger = LoggerFactory.getLogger(DirectURLService.class); private static final long serialVersionUID = 9188067506635747901L; DataProvider dataProvider; boolean hasNodeReadRight = false; boolean hasNodeWriteRight = false; HttpSession session; ArrayList<String> ourIPs = new ArrayList<String>(); @Override public void init( ServletConfig config ) throws ServletException { super.init(config); /// List possible local address try { dataProvider = SqlUtils.initProvider(getServletContext(), logger); Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); while (interfaces.hasMoreElements()){ NetworkInterface current = interfaces.nextElement(); if (!current.isUp() || current.isLoopback() || current.isVirtual()) continue; Enumeration<InetAddress> addresses = current.getInetAddresses(); while (addresses.hasMoreElements()){ InetAddress current_addr = addresses.nextElement(); if (current_addr instanceof Inet4Address) ourIPs.add(current_addr.getHostAddress()); } } } catch( Exception e ) { } } public void initialize(HttpServletRequest httpServletRequest) { } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { String val = request.getParameter("i"); /// Decrypt data Cipher rc4; String output=""; try { byte[] data = stringToHex(val.toCharArray()); rc4 = Cipher.getInstance("RC4"); String secretkey = ConfigUtils.get("directkey"); SecretKeySpec key = new SecretKeySpec(secretkey.getBytes(), "RC4"); rc4.init(Cipher.DECRYPT_MODE, key); byte[] ciphertext = rc4.update(data); output = new String(ciphertext); } catch( NoSuchAlgorithmException e ) { e.printStackTrace(); } catch( NoSuchPaddingException e ) { e.printStackTrace(); } catch( InvalidKeyException e ) { e.printStackTrace(); } catch( ArrayIndexOutOfBoundsException e ) { e.printStackTrace(); } /// Keeping access log Date date = new Date(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); BufferedWriter log = LogUtils.getLog("directAccess.log"); String datestring = dateFormat.format(date); /// Check case we are in, act accordingly String[] splitData = output.split(" "); String uuid = splitData[0]; String email = splitData[1]; String role = splitData[2]; int level = Integer.parseInt(splitData[3]); if( "unlimited".equals(splitData[4]) ) { // Log access log.write("["+datestring+"] Direct link access by: "+email+ " ("+role+") for uuid: "+uuid+" level: "+level+" duration: "+splitData[4]); } else { int duration = Integer.parseInt(splitData[4]); // In hours (minimum 1h) long endtime = 0; if( splitData.length == 6 ) endtime = Long.parseLong(splitData[5]); /// Check if link is still valid long currtime = date.getTime()/1000; if( currtime > endtime ) { log.write("["+datestring+"] Old link access by: "+email+ " ("+role+") for uuid: "+uuid+" level: "+level+" duration: "+duration+" ends at: "+endtime); log.newLine(); log.flush(); log.close(); response.setStatus(403); response.getWriter().close(); request.getInputStream().close(); } else { // Log connection attempt. email, uuid, role access, hour, ip, date log.write("["+datestring+"] Direct link access by: "+email+ " ("+role+") for uuid: "+uuid+" level: "+level+" duration: "+duration+" ends at: "+endtime); log.newLine(); log.flush(); log.close(); } } /// log in person with associated email Connection c = null; try { /// Init DB connection c = SqlUtils.getConnection(getServletContext()); session = request.getSession(true); boolean isLogged = false; Integer uidcheck = (Integer) session.getAttribute("uid"); int uid = 0; if( uidcheck != null ) { uid = uidcheck; isLogged = true; } String[] login = null; switch( level ) { case 4: // Just log as public (world) if( !isLogged ) { int pubid = 0; /// Find public id and log as such String sql = "SELECT userid FROM credential WHERE login='public'"; PreparedStatement st = c.prepareStatement(sql); ResultSet rs = st.executeQuery(); rs.next(); pubid = rs.getInt(1); session.setAttribute("user", "public"); session.setAttribute("uid", pubid); } break; case 3: // Create account for this person /// Check if user exist by logging in login = dataProvider.logViaEmail(c, email); if( login != null ) { uid = Integer.parseInt(login[2]); session.setAttribute("user", login[1]); session.setAttribute("uid", uid); session.setAttribute("source", "public.htm"); String referer = (String) request.getHeader("referer"); // Can be spoofed System.out.println("Login from source: "+referer); isLogged = true; } else if( !isLogged ) { login = new String[] {"0","0","0"}; try { login[2] = dataProvider.createUser(c, email, email); uid = Integer.parseInt(login[2]); } catch(Exception e){} // } case 2: // Share portfolio if( uid > 0 ) { /// Find group for this node int rrgid = dataProvider.getRoleByNode(c, 1, uuid, role); /// Put person in specified group String userInfo = "<users><user id='"+uid+"' /></users>"; dataProvider.postRRGUsers(c, 1, rrgid, userInfo); } // dataProvider.disconnect(); case 1: // Temp login if( !isLogged ) { login = dataProvider.logViaEmail(c, email); uid = Integer.parseInt(login[2]); /// Log person session.setAttribute("user", login[1]); session.setAttribute("uid", uid); session.setAttribute("source", "public.htm"); String referer = (String) request.getHeader("referer"); // Can be spoofed System.out.println("Login from source: "+referer); } break; case 0: // Just ask for login break; } if( login != null ) // If account exists { //// FIXME: Make it so we create account and put this new account in the uuid/role group // TODO /* ///// Check if uuid hasn't been shared already in a previous call (specific table) /// Prevent sharing with another personal account after being evaluated. /// Since the specific group will be the username (specific rights), /// we can also know if student tried sharing it with self first ///// Check if this user is not giving rights to self (existing user account) ///// Check if user has some access to this uuid /// Prevent somebody else to share another student node ///// Check if user has right to share //// Put person in specified group //*/ /// Check if person exist } else // User doesn't exists { } } catch( Exception e ) { e.printStackTrace(); uuid = ""; } finally { try { if( c != null ) c.close(); } catch( SQLException e ){ e.printStackTrace(); } } PrintWriter writer = response.getWriter(); writer.write(uuid); writer.close(); request.getInputStream().close(); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { /// Check if user is logged in HttpSession session = request.getSession(false); if( session == null ) return; int uid = (Integer) session.getAttribute("uid"); if( uid == 0 ) return; /// TODO: From UUID, check metadata attribute "secure" and redirect to specific url for direct log in /// Manage and keep different case number String uuid = request.getParameter("uuid"); String email = request.getParameter("email"); String role = request.getParameter("role"); String level = request.getParameter("l"); String duration = request.getParameter("d"); if(duration == null) duration = "72"; // Default 72h String endtimeString = ""; if( "unlimited".equals(duration) ) { endtimeString = duration; } else { int durationInt = Integer.parseInt(duration); if( durationInt < 1 ) durationInt = 1; else if( durationInt > 24*30 ) // 720 hours, 30 days durationInt = 24*30; Date current = new Date(); long endtime = current.getTime()/1000 + durationInt*3600; // Number of seconds endtimeString = Long.toString(endtime); } /// Keeping creation log BufferedWriter log = LogUtils.getLog("directAccess.log"); Date date = new Date(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); String datestring = dateFormat.format(date); log.write("["+datestring+"] Direct link creation for user: "+uid+" for access at: "+uuid+" with email: "+email+ " ("+role+"). Access level: '"+level+"' for duraction: '"+duration+"' ending at: '"+endtimeString+"'"); log.newLine(); log.flush(); log.close(); /// Encrypt nodeuuid email role String output = ""; try { String data = uuid+" "+email+" "+role+" "+level+" "+duration+" "+endtimeString; Cipher rc4 = Cipher.getInstance("RC4"); String secretkey = ConfigUtils.get("directkey"); SecretKeySpec key = new SecretKeySpec(secretkey.getBytes(), "RC4"); rc4.init(Cipher.ENCRYPT_MODE, key); byte[] clear = rc4.update(data.getBytes()); output = hexToString(clear); } catch( NoSuchAlgorithmException e ) { e.printStackTrace(); } catch( NoSuchPaddingException e ) { e.printStackTrace(); } catch( InvalidKeyException e ) { e.printStackTrace(); } /// Return encrypted data PrintWriter writer = response.getWriter(); writer.write(output); writer.close(); request.getInputStream().close(); } final protected static char[] resolveHex = "0123456789ABCDEF".toCharArray(); public static String hexToString(byte[] bytes) { StringBuilder hexchars = new StringBuilder(bytes.length * 2); for ( int j = 0; j < bytes.length; j++ ) { hexchars.append(resolveHex[(bytes[j] & 0xFF) >>> 4]); hexchars.append(resolveHex[(bytes[j] & 0xFF) & 0x0F]); } return hexchars.toString(); } // speed vs space final protected static char[] resolveChar = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,0,0, 0,0,0,0,0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,11,12, 13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; public static byte[] stringToHex(char[] s) { int len = s.length>>1; byte[] data = new byte[len]; for (int i = 0; i < len; ++i) { data[i] = (byte) (resolveChar[s[i<<1]] << 4 | resolveChar[s[(i<<1)+1]]); } return data; } }