You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by co...@locus.apache.org on 2000/02/17 22:19:03 UTC
cvs commit: jakarta-tomcat/src/share/org/apache/tomcat/servlets AuthServlet.java DefaultErrorPage.java JSecurityCheck.java
costin 00/02/17 13:19:02
Modified: src/share/org/apache/tomcat/core Container.java
RequestImpl.java
src/share/org/apache/tomcat/request SecurityCheck.java
SimpleMapper.java
src/share/org/apache/tomcat/servlets AuthServlet.java
DefaultErrorPage.java JSecurityCheck.java
Added: src/etc tomcat-users.xml
src/examples/jsp/security/login login.jsp
Removed: src/examples/jsp/security login.jsp
Log:
BUGFIX: fixed various bugs in error processing, security checking, form-based
login.
ADDED:
- simple user database ( tomcat-users.xml ) - it's very limited, but should
work for standalone tomcat - and we want to plug an existing powerfull auth,
not to design one ( based on Craig's security code, I simplified it a bit to
be able to get it done )
- error handler will log the stack traces.
- few more messages and traces if debug is enabled.
- Removed an obvious hole - after authentication we'll save a private object
in the session, instead of a "String username". The only way you can create the
Credential is via SecurityCheck, that means a trojan servlet can't influence
another application.
Also: tested form login, it seems to work - fill bugs in
jakarta.apache.org/bugs !!!
Revision Changes Path
1.1 jakarta-tomcat/src/etc/tomcat-users.xml
Index: tomcat-users.xml
===================================================================
<tomcat-users>
<user name="tomcat" password="tomcat" roles="tomcat" />
</tomcat-users>
1.1 jakarta-tomcat/src/examples/jsp/security/login/login.jsp
Index: login.jsp
===================================================================
<html>
<body>
<h1>Login page for examples</h1>
<form method="POST" action="j_security_check" >
<input type="text" name="j_username">
<input type="password" name="j_password">
<input type="submit" name="j_security_check">
</form>
</body>
</html>
1.12 +22 -1 jakarta-tomcat/src/share/org/apache/tomcat/core/Container.java
Index: Container.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/Container.java,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- Container.java 2000/02/16 05:44:33 1.11
+++ Container.java 2000/02/17 21:19:01 1.12
@@ -86,7 +86,7 @@
* map via addMapping() callback. It can set private informations as
* attributes ( the Mapper or security interceptors will probably do so ).
*/
-public class Container {
+public class Container implements Cloneable {
// The main difference between this container and Catalina
// is that in Catalina, Container has an invoke() method.
@@ -242,4 +242,25 @@
public void setRoles( String roles[] ) {
this.roles=roles;
}
+
+ public String toString() {
+ StringBuffer sb=new StringBuffer();
+ sb.append( "Ct (" );
+ if( handler!= null) sb.append( handler.toString() );
+ if( roles!=null) {
+ sb.append(" Roles: ");
+ for( int i=0; i< roles.length; i++ )
+ sb.append(" ").append( roles[i]);
+ }
+ sb.append( " )");
+ return sb.toString();
+ }
+
+ public Container getClone() {
+ try {
+ return (Container)this.clone();
+ } catch( CloneNotSupportedException ex ) {
+ return this;
+ }
+ }
}
1.21 +13 -5 jakarta-tomcat/src/share/org/apache/tomcat/core/RequestImpl.java
Index: RequestImpl.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/RequestImpl.java,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -r1.20 -r1.21
--- RequestImpl.java 2000/02/17 12:15:03 1.20
+++ RequestImpl.java 2000/02/17 21:19:01 1.21
@@ -1,7 +1,7 @@
/*
- * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/RequestImpl.java,v 1.20 2000/02/17 12:15:03 shachor Exp $
- * $Revision: 1.20 $
- * $Date: 2000/02/17 12:15:03 $
+ * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/RequestImpl.java,v 1.21 2000/02/17 21:19:01 costin Exp $
+ * $Revision: 1.21 $
+ * $Date: 2000/02/17 21:19:01 $
*
* ====================================================================
*
@@ -694,8 +694,16 @@
public String toString() {
StringBuffer sb=new StringBuffer();
- sb.append( "R( " + getRequestURI() + " ");
- if( context!=null) sb.append( context.getPath() );
+ sb.append( "R( ");
+ if( context!=null) {
+ sb.append( context.getPath() );
+ if( getServletPath() != null )
+ sb.append( " + " + getServletPath() + " + " + getPathInfo());
+ else
+ sb.append( " + " + getLookupPath());
+ } else {
+ sb.append(getRequestURI());
+ }
sb.append(")");
return sb.toString();
}
1.5 +117 -16 jakarta-tomcat/src/share/org/apache/tomcat/request/SecurityCheck.java
Index: SecurityCheck.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/request/SecurityCheck.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- SecurityCheck.java 2000/02/17 07:52:21 1.4
+++ SecurityCheck.java 2000/02/17 21:19:02 1.5
@@ -62,10 +62,12 @@
import org.apache.tomcat.core.*;
import org.apache.tomcat.util.*;
+import org.apache.tomcat.util.xml.*;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.servlet.http.*;
+import org.xml.sax.*;
/**
* Will process the request and determine the session Id, and set it
@@ -77,13 +79,24 @@
*
*/
public class SecurityCheck extends BaseInterceptor {
-
+ MemoryRealm memoryRealm;
+
public SecurityCheck() {
}
public void contextInit( Context ctx)
throws TomcatException
{
+ if( memoryRealm==null) {
+ memoryRealm = new MemoryRealm(ctx);
+ try {
+ memoryRealm.readMemoryRealm(ctx);
+ } catch(Exception ex ) {
+ ex.printStackTrace();
+ memoryRealm=null;
+ }
+ }
+
if( "FORM".equals( ctx.getAuthMethod() )) {
ServletWrapper jcheck=new ServletWrapper();
jcheck.setContext( ctx );
@@ -151,16 +164,25 @@
HttpSession session=req.getSession( false );
if( session == null )
return 0; // not authenticated
- String username=(String)session.getAttribute("j_username");
- String password=(String)session.getAttribute("j_password");
-
- if( ctx.getDebug() > 0 ) ctx.log( "Form Auth: " + username + " " + password);
- if( checkPassword( username, password ) ) {
- req.setRemoteUser( username );
+ Credential cr=(Credential) session.getAttribute( "tomcat.credential");
+ if( cr!=null ) {
+ req.setRemoteUser( cr.username );
+ // maybe we can set the role(s) too...
} else {
- // wrong password
- errorPage( req, response );
- }
+ // it wasn't authenticated, maybe it's a new login
+ String username=(String)session.getAttribute("j_username");
+ String password=(String)session.getAttribute("j_password");
+ if( ctx.getDebug() > 0 ) ctx.log( "Form Auth: " + username + " " + password);
+ if( username!=null && checkPassword( username, password ) ) {
+ req.setRemoteUser( username );
+ Credential c=new Credential();
+ c.username=username;
+ session.setAttribute( "tomcat.credential", c );
+ } else {
+ // wrong password
+ errorPage( req, response );
+ }
+ }
}
return 0;
@@ -183,15 +205,15 @@
}
String user=req.getRemoteUser();
+ if( ctx.getDebug() > 0 ) ctx.log( "Controled access for " + user + " " + req + " " + req.getContainer() );
if( user!=null ) {
- if( ctx.getDebug() > 0 ) ctx.log( "Controled access for " + user );
for( int i=0; i< roles.length; i++ ) {
if( userInRole( user, roles[i] ) )
return 0;
}
}
- if( ctx.getDebug() > 0 ) ctx.log( "Unauthorized " + user);
+ if( ctx.getDebug() > 0 ) ctx.log( "Unauthorized " + user + " " + req.getContainer());
return HttpServletResponse.SC_UNAUTHORIZED;
// XXX check transport
}
@@ -240,12 +262,91 @@
}
private boolean checkPassword( String user, String pass ) {
- System.out.println("Checking " + user + " " + pass );
- return true;
+ if( memoryRealm != null ) return memoryRealm.checkPassword( user, pass );
+ return false;
}
private boolean userInRole( String user, String role ) {
- System.out.println("Checking role " + user + " " + role );
- return true;
+ if( memoryRealm != null ) return memoryRealm.userInRole( user, role );
+ return false;
+ }
+
+}
+
+class MemoryRealm {
+ // String user -> password
+ Hashtable passwords=new Hashtable();
+ // String role -> Vector users
+ Hashtable roles=new Hashtable();
+ Context ctx;
+
+ MemoryRealm(Context ctx) {
+ this.ctx=ctx;
+ }
+
+ public void addUser(String name, String pass, String groups ) {
+ ctx.log( "Add user " + name + " " + pass + " " + groups );
+ passwords.put( name, pass );
+ addRole( groups, name );
}
+
+ public void addRole( String role, String user ) {
+ Vector users=(Vector)roles.get(role);
+ if(users==null) {
+ users=new Vector();
+ roles.put(role, users );
+ }
+ users.addElement( user );
+ }
+
+ public boolean checkPassword( String user, String pass ) {
+ ctx.log( "check " + user+ " " + pass + " " + passwords.get( user ));
+ return pass.equals( (String)passwords.get( user ) );
+ }
+
+ public boolean userInRole( String user, String role ) {
+ Vector users=(Vector)roles.get(role);
+ ctx.log( "check role " + user+ " " + role + " " );
+ if(users==null) return false;
+ return users.indexOf( user ) >=0 ;
+ }
+
+ void readMemoryRealm(Context ctx) throws Exception {
+ ContextManager cm=ctx.getContextManager();
+ String home=cm.getHome();
+ File f=new File( home + "/conf/tomcat-users.xml");
+ if( ! f.exists() ) {
+ ctx.log( "File not found " + f );
+ return;
+ }
+ XmlMapper xh=new XmlMapper();
+ if( ctx.getDebug() > 5 ) xh.setDebug( 2 );
+
+ // call addUser using attributes as parameters
+ xh.addRule("tomcat-users/user",
+ new XmlAction() {
+ public void start( SaxContext ctx) throws Exception {
+ int top=ctx.getTagCount()-1;
+ MemoryRealm mr=(MemoryRealm)ctx.getRoot();
+ AttributeList attributes = ctx.getAttributeList( top );
+ String user=attributes.getValue("name");
+ String pass=attributes.getValue("password");
+ String group=attributes.getValue("roles");
+ mr.addUser( user, pass, group );
+ }
+ }
+ );
+
+ xh.readXml( f, this );
+ }
+}
+
+
+class Credential {
+ Credential() {}
+
+ String username;
+ String realm;
+ String role;
+
}
1.14 +25 -16 jakarta-tomcat/src/share/org/apache/tomcat/request/SimpleMapper.java
Index: SimpleMapper.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/request/SimpleMapper.java,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- SimpleMapper.java 2000/02/16 07:06:22 1.13
+++ SimpleMapper.java 2000/02/17 21:19:02 1.14
@@ -171,8 +171,6 @@
String ctxP=context.getPath();
Mappings m=(Mappings)contextPaths.get(ctxP);
- if(debug>0) context.log( "Mapping: " + req );
-
container=findContainer( m, path, context, req );
// set default container, return
@@ -185,18 +183,16 @@
req.setWrapper( m.defaultContainer.getHandler() );
req.setServletPath( "" );
req.setPathInfo( path);
- if(debug>0) context.log("Default mapper " + "\n " + req);
} else {
req.setWrapper( container.getHandler() );
-
- if(debug>0) context.log("Found wrapper using getMapPath " + "\n " + req);
}
+ if(debug>0) context.log("SM: Handler " + req + " " + container );
req.setContainer( container );
// the container already has security properties
// in it, no need to search again
if( container.getRoles() != null ) {
- if(debug>0) context.log("Existing security constraint " + "\n " + container.getRoles());
+ if(debug>0) context.log("Existing security constraint " + container.toString());
return OK;
}
@@ -210,10 +206,20 @@
}
// Merge the security info into the container
//
- if(debug>0) context.log("Found security constraing " + "\n " + scontainer.getRoles());
- container.setRoles( scontainer.getRoles());
- container.setTransport( scontainer.getTransport());
-
+ // XXX merging is a very usefull optimization, but we should do it
+ // at init time, it's very expensive because we need to be sure it has the same
+ // pattern !!
+ // if(debug>0) context.log("Merging security constraint " + scontainer + " into " + container );
+ // container.setRoles( scontainer.getRoles());
+ // container.setTransport( scontainer.getTransport());
+
+ // until merging is implemented, we'll just create a new container with the combined
+ // properties. This code needs optimizations ( i.e. alghoritm + data, not OptimizeIt!)
+ Container ct=container.getClone();
+ ct.setRoles( scontainer.getRoles());
+ ct.setTransport( scontainer.getTransport());
+ req.setContainer( ct );
+ if(debug>0) context.log("Set security constraings " + req + " " + container );
return OK;
}
@@ -337,7 +343,7 @@
Container wrapper = null;
wrapper = (Container)m.pathMappedServlets.get(path);
- if (wrapper != null) {
+ if (wrapper != null && wrapper.getHandler() != null ) {
req.setServletPath( path );
// No path info - it's an exact match
if(debug>1) context.log("path match " + path );
@@ -359,7 +365,7 @@
while (s.length() > 0) {
// XXX we can remove /* in prefix map when we add it, so no need
// for another string creation
- if(debug>2) context.log( "Prefix: " + s );
+ // if(debug>8) context.log( "Prefix: " + s );
wrapper = (Container)m.prefixMappedServlets.get(s + "/*" );
//Enumeration en=m.prefixMappedServlets.keys();
//while( en.hasMoreElements() ) {
@@ -371,16 +377,17 @@
else
break;
}
-
+
// Set servlet path and path info
- if( wrapper != null ) {
+ if( wrapper != null && wrapper.getHandler() != null ) {
// Found a match !
req.setServletPath( s );
String pathI = path.substring(s.length(), path.length());
if( ! "".equals(pathI) )
req.setPathInfo(pathI);
- if(debug>0) context.log("prefix match " + path );
}
+ if(wrapper!= null )
+ if(debug>0) context.log("prefix match " + path + " " + wrapper );
return wrapper;
}
@@ -397,6 +404,9 @@
if (wrapper == null)
return null;
+ if(debug>0) context.log("extension match " + path );
+
+ if( wrapper.getHandler() ==null) return wrapper;
// fix paths
// /a/b/c.jsp/d/e
int i = path.lastIndexOf(".");
@@ -412,7 +422,6 @@
req.setServletPath( path );
}
- if(debug>0) context.log("extension match " + path );
return wrapper;
}
1.3 +1 -1 jakarta-tomcat/src/share/org/apache/tomcat/servlets/AuthServlet.java
Index: AuthServlet.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/servlets/AuthServlet.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- AuthServlet.java 2000/02/17 07:52:24 1.2
+++ AuthServlet.java 2000/02/17 21:19:02 1.3
@@ -100,7 +100,7 @@
// rd.include( request, response );
session.setAttribute( "tomcat.auth.originalLocation", req.getRequestURI());
- ctx.log("Setting orig location " + req.getRequestURI());
+ if( ctx.getDebug() > 0 ) ctx.log("Setting orig location " + req.getRequestURI());
if( ! page.startsWith("/")) page="/" + page;
response.sendRedirect( ctx.getPath() + page );
return;
1.5 +1 -0 jakarta-tomcat/src/share/org/apache/tomcat/servlets/DefaultErrorPage.java
Index: DefaultErrorPage.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/servlets/DefaultErrorPage.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- DefaultErrorPage.java 2000/02/17 07:52:24 1.4
+++ DefaultErrorPage.java 2000/02/17 21:19:02 1.5
@@ -94,6 +94,7 @@
Throwable e= (Throwable)request.getAttribute("tomcat.servlet.error.throwable");
if( e!=null ) {
+ e.printStackTrace();
sendError(request, response, 500, exceptionString( e ));
return;
}
1.2 +2 -3 jakarta-tomcat/src/share/org/apache/tomcat/servlets/JSecurityCheck.java
Index: JSecurityCheck.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/servlets/JSecurityCheck.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- JSecurityCheck.java 2000/02/17 07:52:24 1.1
+++ JSecurityCheck.java 2000/02/17 21:19:02 1.2
@@ -80,7 +80,6 @@
{
Request req=((HttpServletRequestFacade)request).getRealRequest();
Context ctx=req.getContext();
- ctx.log( "In JSecurityCheck");
HttpSession session=req.getSession( false );
if( session == null ) {
ctx.log("TRY TO AUTHENTICATE WITHOUT A SESSION " + req);
@@ -88,13 +87,13 @@
}
String username=req.getFacade().getParameter( "j_username" );
String password=req.getFacade().getParameter( "j_password" );
- if( ctx.getDebug() > 0 ) ctx.log( "FORM auth " + username + " " + password );
+ if( ctx.getDebug() > 0 ) ctx.log( "JSecurityCheck - FORM auth " + username + " " + password );
session.setAttribute( "j_username", username );
session.setAttribute( "j_password", password );
String origLocation=(String)session.getAttribute( "tomcat.auth.originalLocation");
- ctx.log("Back to orig location " + origLocation);
+ if( ctx.getDebug() > 0) ctx.log("JSecurityCheck - Back to orig location " + origLocation);
response.sendRedirect( origLocation );
}