 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Cookie;

import java.io.*;
import java.util.Date;
import java.text.DateFormat;
import java.util.Iterator;
import java.util.Enumeration;
import java.util.Hashtable;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.CallableStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.Types;


public class PolicyServlet extends HttpServlet
{  
  Connection conn ;

  Connection getConnection() {
    if ( conn == null ) {
      try {
        conn = DriverManager.getConnection("jdbc:oracle:kprb:");
      } catch ( SQLException ex ) {
      }
    }
    return conn;
  }


  public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException
  {
    response.setContentType("text/html");
    Generate g = new Generate(request, response, true);
    g.printHeader();
    g.printActions();
    g.printTable();
    g.printTrailer();
  }

  public void doPost(HttpServletRequest request, 
                     HttpServletResponse response) 
    throws IOException
  {
    response.setContentType("text/html");
    Generate g = new Generate(request, response, false);
    String[] kind = request.getParameterValues("kind");
    if ( kind.length != 1 ) {
      g.pBadPost();
    } else if ( kind[0].equals("disable") ) {
      g.doDisable();
    } else if ( kind[0].equals("enable") ) {
      g.doEnable();
    } else if ( kind[0].equals("select") ) {
      g.doSelect(); 
   } else if ( kind[0].equals("GRANT") ) {
      g.doCreateRow(kind[0]);
    } else if ( kind[0].equals("RESTRICT") ) {
      g.doCreateRow(kind[0]);
    } else if ( kind[0].equals("DELETE") ) {
      g.doDelete();
    } else {
      g.pBadPost();
    }
    g.printActions();
    g.printTable();
    g.printTrailer();
  }
  
  class Generate {
    PrintWriter out;
    HttpServletRequest request; 
    HttpServletResponse response;
    Cookie[] cookies;
    Hashtable selparam;
    

    Generate( HttpServletRequest request, 
              HttpServletResponse response, 
              boolean init_out) throws IOException {

      // Have to do this due to cookie stuff
      if(init_out == true)
        this.out = response.getWriter();
      this.request = request;
      this.response = response;
      this.cookies = request.getCookies();
      this.selparam = new Hashtable();
    }
    

    void setCookie(String key, String value)
    {
      Cookie ck = new Cookie(key,value);
      response.addCookie(ck);
    }

    String getCookie(String key)
    {
      
      Cookie ck = null;
      
      for(int i = 0; i < cookies.length; i++)
      {
        ck = cookies[i];
        if(ck.getName().equals(key))
          return ck.getValue();
      }
      return null;
    }
    
    void printHeader() {
      p("<html><head><title>Policy Table</title></head>");
      p("<body>");
    }

    void printTrailer() {
      p("</body>");
      p("</html>");
    }      
    
    void printTable() {
      p("<center><table BORDER=\"1\" WIDTH=\"90%\" >");
      p("<caption>Jave Security Policy Table </caption>");
      printTableBody();
      p("</table></center>");
    }

    void printTableBody() {
      Connection conn = getConnection();
      Statement stmt = null;
      ResultSet rs = null;
      String Table = 
        (request.isUserInRole("DBA") ? "dba_java_policy":"user_java_policy");
      
      try {
        stmt = conn.createStatement() ;
        rs = stmt.executeQuery("select * from " + Table + " order by seq") ;
        while ( rs.next() ) {
          printRow(getRow(rs));
        }
      } catch ( SQLException ex ) {
        out.println("Exception " + ex) ;
        ex.printStackTrace(out);
      } finally {
        if ( rs != null ) {
          try {
            rs.close();
          } catch ( SQLException ignore ) { }
        }
        if ( stmt != null ) {
          try {
            stmt.close();
          } catch ( SQLException ignore ) { } 
        }
      }
    }

    RowData getRow(ResultSet rs) {
      return new RowData(rs);
    }
      
    RowData getRow(long key) {
      RowData row = null;
      Connection conn = getConnection();
      PreparedStatement stmt = null;
      ResultSet rs = null;
      String Table = 
        (request.isUserInRole("DBA") ? "dba_java_policy":"user_java_policy");

      try {
        stmt = 
          conn.prepareStatement("select * from " + Table + " where seq = ?" ) ;
        stmt.setLong(1, key);
        rs = stmt.executeQuery() ;
        if ( rs.next() ) {
          row = getRow(rs);
        } 
      } catch ( SQLException ex ) {
        p("Exception " + ex) ;
        ex.printStackTrace(out);
      } finally {
        if ( rs != null ) {
          try {
            rs.close();
          } catch ( SQLException ignore ) { }
        }
        if ( stmt != null ) {
          try {
            stmt.close();
          } catch ( SQLException ignore ) { } 
        }
      }
      return row;
    }

    String qt(String s) {
      return "\"" + s + "\"";
    }

    String simpleName(String name) {
      int x =  name.lastIndexOf(".") ;
      if ( x > 0 ) {
        name = name.substring(x + 1);
      }
      return name;
    }

    String qt(int n) {
      return qt(Integer.toString(n));
    }

    String self() {
      return qt(response.encodeURL(request.getRequestURI()));
    }
    
    void pButton(String button, String data) {
      p("<form action= " + self());
      p("  method=\"post\" >");
      p("  <input type = \"hidden\" name = \"data\" ");
      p("         value = " + qt(data) + ">");
      p("  <input type = \"hidden\" name = \"kind\" ");
      p("         value = " + qt(button) + ">");
      p("  <input type=\"submit\" " +
        "         value = " + qt(button) + ">");
      p("</form>");
    }

    void pRowToggle(RowData row) {
      String action ;
      if ( row.enabled.equals("ENABLED")) {
        action = "disable";
      } else {
        action = "enable" ;
      }
      String sKey = Long.toString(row.seq);
      p("<td>"); pButton(action, sKey); p("</td>");
      p("<td>"); pButton("select", sKey); p("</td>");
    }

    void printRow(RowData row) throws SQLException {
      p("<tr>");
      pRowToggle(row);
      printTD(Long.toString(row.seq));
      printTD(row.kind);
      printTD((row.grantee));
      p("<td>" + row.type_name + "</td>");
      printTD(row.name);
      printTD(row.action);
      printTD(row.enabled);
      p("</tr>");
    }

    void printTD(String s) {
      p("<td>" + s + "</td>");
    }

    void pFormLine(String description, String name, int length) {
      p("<tr>");
      String value = (String)selparam.get(name);
      String vAttribute = "";
      if ( value != null ) {
        vAttribute = " value=" + qt(value);
      }
      printTD(description);
      p("<td><input type=\"text\" name= " + qt(name) + 
        "     size= " + qt(length) + vAttribute + "> </td>");
      p("</tr>");
    }

    void printActions() {
      printGrantAction();
      printDeleteAction();
    }

    void printGrantAction() {
      p("<p>To create or enable a row enter its content here.");
      p("An easy way to initialize the values is to click ");
      p("a select button on some row");
      p("If a Permission does not have a public synonym");
      p("prefix its name with the schema containing it.");
      p("Note that that these fields are case sensitive.");
      p("Most user names will need to be entered in all caps.");
      p("<form action =" + self() + " method=\"post\">" );
      p("<table>");
      pFormLine("Grantee ", "grantee", 30);
      pFormLine("Full name of a Permission class", "permission", 60);
      pFormLine("Target (aka name) argument of the Permission", "target", 60);
      pFormLine("Action argument of Permission", "action",40);
      p("<tr>");
      p("<td><input type=\"submit\" name=kind value=\"GRANT\"></td>");
      p("<td ALIGN=RIGHT><input type=\"submit\" name=kind value=RESTRICT></td>");
      p("</tr>");
      p("</table>");
      p("</form>");
      p("Be aware that a 'RESTRICT' row is not a negative grant.");
      p("What it does is require explicit GRANT's for particular Permissions");
      p("<hr>");
    }

    void printDeleteAction() {
      p("<p>To delete a row enter its number here. ");
      p("Only disabled rows can be deleted");
      p("<form action =" + self() + " method=\"post\">" );
      p("<table>");
      pFormLine("Row Number ", "key", 10);
      p("<tr><td><input type=submit name=kind value=\"DELETE\"></td></tr>");
      p("</table></form>");
      p("<hr>");
    }

    void pBadPost() {
      p("<p>A malformed post was recieved </p>");
      Enumeration params = request.getParameterNames();
      while( params.hasMoreElements() ) {
        String name = (String)params.nextElement() ;
        p(name + "<br>");
        p("------<br>");
        String[] values = request.getParameterValues(name);
        for ( int xValue = 0 ; xValue < values.length ; ++ xValue ) {
          p(values[xValue] + "<br>");
        }
        p("<br>");
      }
      p("<p>ATTRIBUTES</p>");
      Enumeration attributes = request.getAttributeNames();
      while( attributes.hasMoreElements() ) {
        String att = (String)attributes.nextElement() ;
        p(att + "<br>");
        p("------<br>");
        String value = request.getAttribute(att).toString();
        p(value + "<br>");
        p("<br>");
      }
      new RuntimeException("").printStackTrace(out);
    }

    /* If the row has not been disabled then this will do 
     * nothing
     */
    void doDelete() {
      Connection conn = getConnection();
      CallableStatement stmt = null;
      String sKey = get("key");
      long key = Long.parseLong(sKey);
      try
      {
        stmt = conn.prepareCall("{call dbms_java.delete_permission(?)}");
        stmt.setLong(1,key);
        stmt.execute();
      }
      catch (SQLException ex)
      {
        p("Exception " + ex) ;
        ex.printStackTrace(out);
      } finally {
        if ( stmt != null ) {
          try {
            stmt.close();
          } catch ( SQLException ignore ) { } 
        }
      }
      setCookie("key", sKey);
    }
  
    void doCreateRow(String what) {
      String schema = get("grantee");
      String type = get("permission");
      String name = get("target");
      String action = get("action");

      setCookie("grantee", schema);
      setCookie("permission", type);
      setCookie("target", name);
      setCookie("action", action);

      long r = -1;
      String a = action;
      if ( action.length() == 0 ) {
        a = null;
      }

      Connection conn = getConnection();
      CallableStatement stmt = null;
      String proc = null;
      boolean secex = false;
      
      if ( what.equals("GRANT")) {
        proc = "{call dbms_java.grant_permission(?,?,?,?,?)}";
      } 
      else if ( what.equals("RESTRICT")) {
        proc = "{call dbms_java.grant_permission(?,?,?,?,?)}";
      }

      if(proc != null){
        try{
          stmt = conn.prepareCall(proc);
          stmt.setString(1,schema);
          stmt.setString(2,type);
          stmt.setString(3,name);
          stmt.setString(4,action);
          stmt.registerOutParameter(5, Types.INTEGER);
          stmt.execute();
          r = stmt.getLong(5);
        }
        catch (SQLException ex)
        {
          if(ex.getErrorCode() == 29532 && 
             ex.getMessage().lastIndexOf("java.lang.SecurityException") > 0)
          {
            p("Oracle security exception for policy table update");
            secex = true;
          }
          else
          {
            
            p("Exception " + ex) ;
            ex.printStackTrace(out);
           }
        }
        finally{
          try{
            if(stmt != null)
              stmt.close();
          } catch(SQLException ignore){
          }
        }
        setCookie("key",Long.toString(r));
        if(r < 0 && secex == false){
          p("<p> " + type + " is not the name of a class or " + schema + 
            " is not the name of a user or role</p>");
        }
        else if(r > 0)
        {
          p("<p>Row " + r + " is created or enabled");
        }
        
      } else {
        setCookie("key", "-1");
        p("<p>Request not recognized");
      }
    }

    
    void p(String msg){
      if(out == null)
      {
        
        try{
          out = response.getWriter();
        }
        catch(IOException io)
        {
          System.out.println("getWriter failed : " + io.getMessage());
        }
      }
      
      out.println(msg);
    }

    String get(String key) {
      String[] values = request.getParameterValues(key);
      String v = null ;
      if ( values == null || values.length != 1 ) {
        pBadPost();
        return null;
      } else { 
        v = values[0];
      }
      return v;
    }

    String getData() {
      String[] data = request.getParameterValues("data");
      if ( data.length == 1 ) {
        return data[0];
      } else {
        pBadPost();
        return null;
      }
      
    }

    void doDisable() {
      String rowId = get("data") ;
      if ( rowId != null ) {
        setCookie("key", rowId);
        int key = Integer.parseInt(rowId);
        try {
          Connection conn = getConnection();
          CallableStatement stmt = null;
          stmt = conn.prepareCall("{call dbms_java.disable_permission(?)}");
          stmt.setLong(1,key);
          stmt.execute();
          p("<p>Disabled " + key + "</p>");        
        }
        catch (SQLException ex)
        {
          p("Exception " + ex) ;
          ex.printStackTrace(out);
        }
      }
    }

    void doEnable() {
      String rowId = get("data") ;
      if ( rowId != null ) {
        setCookie("key", rowId);
        int key = Integer.parseInt(rowId);
        try {
          Connection conn = getConnection();
          CallableStatement stmt = null;
          stmt = conn.prepareCall("{call dbms_java.enable_permission(?)}");
          stmt.setLong(1,key);
          stmt.execute();
          p("<p>Enabled " + key + "</p>");
        }
        catch (SQLException ex)
        {
          p("Exception " + ex) ;
          ex.printStackTrace(out);
        }
      }
    }

    void doSelect() {
      String sKey = get("data");
      if ( sKey != null ) {
        long key = Long.parseLong(sKey);
        RowData row = getRow(key);
        if ( row != null ) {
          setCookie("key", sKey);
          selparam.put("key", sKey);
          setCookie("grantee", row.grantee);
          selparam.put("grantee", row.grantee);
          setCookie("permission",row.type_schema + ":" + row.type_name);
          selparam.put("permission",row.type_schema + ":" + row.type_name);
          setCookie("target", row.name);
          selparam.put("target", row.name);
          setCookie("action", 
                    (row.action == null ? "" : row.action));
          selparam.put("action", 
                       (row.action == null ? "" : row.action));
        }
      }
    }
  } // Generate

  /*  class to hold the row of interest from 
   *  user_java_policy view.
   */

  class RowData 
  {

    /** Either GRANT or RESTRICT */
    public String kind;
    public String grantee;
    public String type_schema;
    public String type_name;
    public String name;
    public String action;
    /** Either ENABLED  or DISABLED */
    public String enabled;
    public long    seq;

    public RowData(String kind, String grantee, String type_schema,
                   String type_name, String name, String action,
                   String enabled, long seq)
    {
      this.kind = kind;
      this.grantee = grantee;
      this.type_schema = type_schema;
      this.type_name = type_name;
      this.name = name;
      this.action = action;
      this.enabled = enabled;
      this.seq = seq;
    }
    
    public RowData(ResultSet rs)
    {
      try{
        
        kind = rs.getString(1);
        grantee = rs.getString(2);
        type_schema = rs.getString(3);
        type_name = rs.getString(4);
        name = rs.getString(5);
        action = rs.getString(6);
        enabled = rs.getString(7);
        seq = rs.getLong(8);
      }catch (SQLException ex) {
        System.out.println("Exception while building row: " + 
                           ex.getMessage());
      }      
    }      
  }
}
 
