Using Apache/mod_ssl certificate and private key with Tomcat/keytool

2003-11-11 Thread Scott Kelley
Hi,

I have an Apache+mod_ssl+Tomcat configuration that's been working 
fine for several years. I have an SSL certificate from Verisign, and 
my httpd.conf file contains:

SSLCertificateFile /path/to/server.crt
SSLCertificateKeyFile /path/to/server.key
The private key is unencrypted so that the server can restart automatically.

Now I'd like to use the same certificate and private key in a 
Tomcat-only configuration, but I can't quite figure out how to get 
these two pieces of information into keytool for tomcat to use!

It's easy enough to import the certificate:

keytool -import -alias tomcat -file /path/to/server.crt

but I know that the private key needs to be in the keystore too, and 
I haven't been able to figure out how to get it in there!

Simply trying to import it:

keytool -import -alias tomcat -file /path/to/server.key

gives me the message:

keytool error: java.lang.Exception: Input not an X.509 certificate

which doesn't really surprise me because the private key is not an 
X.509 certificate! But how can I tell keytool about my private key?

Can I do this? If so, how? Can I do it with just keytool? Do I need 
to use openssl to tweak something?

I saw some comments in the httpd.conf file (comments added by 
mod_ssl) that suggest the certificate and the private key can be 
combined somehow. Is this what I need to do? If so, how do I do 
this?

Or do I have to toss my old keys and generate a new CSR with keytool? 
The Tomcat tutorial on how to do that seems reasonably 
straightforward. But I would much prefer to use my existing key and 
certificate!

I actually tried this for the first time two years ago. After trying 
everything I could think of, and posting to tomcat-user and getting 
no replies, I gave up and left things the way they were. Now, two 
years later, I *still* can't figure out, or find a recipe, to explain 
how to migrate from an Apache/mod_ssl/Tomcat configuration to a plain 
Tomcat configuration!

Thanks for any help.

Scott

-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


Followup to Valve As Custom Authenticator

2003-06-25 Thread Scott Kelley
I just wanted to follow up on my earlier post, and thank Tim Funk and 
Bill Barker for leading me in the right direction.

It turned out that my Valve code was in fact mostly correct; I was 
just installing it in the wrong place! I had it installed at the 
Engine level, where all sorts of weird things happened. Once I moved 
it to the Host level, everything seemed to start working a whole lot 
better.

For the benefit of anyone who ends up trying to take the same custom 
valve approach to authentication and authorization that we are using, 
here's a short list of things I wish I'd known when starting out 
that would have made things go more quickly:

- Write a Valve that extends ValveBase

- implement Authenticator and Lifecycle in your valve

- implement invoke()

- if the request needs to be logged in, do a redirect

  hres.sendRedirect(hres.encodeRedirectURL(loginPage))

  or, alternately, you can output the login page html
  code directly from the valve
- when the request should be allowed, call

  hrequest.setUserPrincipal(new YourPrincipal(username))
  hrequest.setAuthType(BASIC)
  Other authenticators will see this and not request redundant logins.

- Write your own implementation of Principal.

- To handle authorization, write a Realm.

- To allow a Valve and a Realm to exchange information, use the 
Principal. If both your Realm and your Valve are installed, the 
Principal seen by the Realm will be the one attached to the request 
by your Valve.

- Install both the Valve and the Realm at the top of the Host section 
of server.xml.

- Tomcat uses introspection to handle Valve properties, so you can 
create arbitrary bean-style getters and setters to configure your 
Valve via server.xml.

- Tip: the start() method of the Lifecycle interface is a good place 
to check to see if your Valve has been properly configured. If not, 
you can throw LifecycleException and keep the server from starting up.

Please note that this is NOT a tutorial! You will have to look at the 
Tomcat docs and source code to figure out how to do all this. But the 
above list might make it clearer where to start looking. (And before 
writing to ask me to explain how to do this; please be aware that 
pretty much everything *I* know is in the list above, and even that 
may not be entirely correct! Everything else is in the Tomcat 
source...)

And this list only considers how to talk to Tomcat, not how you 
should be actually authenticating and authorizing requests-- that's a 
separate issue.

Also, for anyone considering this approach, be aware that it's 
reasonably straightforward once you understand Tomcat's architecture, 
but the learning curve is somewhat steep at first! At least that's 
been our experience.

Hope this helps someone,

Scott



-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


Valve as Custom Authenticator

2003-06-11 Thread Scott Kelley
We've had an Apache/Tomcat configuration deployed for a couple years 
now. Authentication is handled by a custom Apache plugin written in 
C. Everything works great and has been quite reliable.

Now we would like to move to a standalone Tomcat configuration and 
have been investigating writing a Valve/Authenticator to replace our 
existing Apache plugin.

I've written a prototype Valve and it does almost everything we need. 
This gives us the ability to require a server-wide login independent 
of how the individual servlet contexts are configured. This ends up 
being Tomcat-specific, but we're ok with that.

The only problem with the current prototype is that if a user hits a 
servlet or JSP in a Context that's configured for basic 
authentication, they still get the browser-generated basic login 
dialog, even after being logged in with our Valve.

In my code, I check for a particular cookie, and if I find it, I set 
the user principal in the request to the appropriate user, something 
like this:

// Has connection already been authenticated
// (i.e. do we have the login cookie?)
Cookie lcookie=ValveUtils.findCookie(hreq,LOGIN_COOKIE_NAME);
// If the request has the login cookie, let it pass through
if (lcookie!=null) {
log(Found login cookie, validating);
if (validLoginCookie(lcookie,hreq)) {
log(cookie is valid, allowing request);
// See AuthenticatorBase.invoke(), which also sets 
authType and userPrincipal
// See SignleSignOn.invoke(), which also set authType and 
userPrincipal
hrequest.getRequest().setUserPrincipal(new 
TempPrincipal(bob_temp_user));
hrequest.getRequest().setAuthType(BASIC);
context.invokeNext(request,response);
} else {
log(cookie not valid, going to error page);
hres.sendRedirect(hres.encodeRedirectURL(ERROR_PAGE_URI));
}
return;
}

I had thought that this would work, because later in the pipeline the 
request hits BasicAuthenticator, which does this:

public boolean authenticate(HttpRequest request,
HttpResponse response,
LoginConfig config)
throws IOException {
// Have we already authenticated someone?
Principal principal =
((HttpServletRequest) request.getRequest()).getUserPrincipal();
if (principal != null) {
if (debug = 1)
log(Already authenticated ' + principal.getName() + ');
return (true);
}
And since I've set the principal to something besides null, I had 
assumed that the basic authentication would just be skipped. Which is 
not the behavior that I'm seeing. Instead, I end up asking the user 
to log in twice: once for my custom Valve (which is a web 
form/redirect thing), and a second time when they hit a servlet in a 
context with basic authentication (which causes the browser to put up 
the basic authentication dialog).

So, what am I missing?

Thanks,

Scott





-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


Re: Valve as Custom Authenticator

2003-06-11 Thread Scott Kelley
SingleSignOn has much the same code as BasicAuthenticator:

in org.apache.catalina.authenticator.SingleSignOn.java:

// Look up the cached Principal associated with this cookie value
if (debug = 1)
log( Checking for cached principal for  + cookie.getValue());
SingleSignOnEntry entry = lookup(cookie.getValue());
if (entry != null) {
if (debug = 1)
log( Found cached principal ' +
entry.principal.getName() + ' with auth type ' +
entry.authType + ');
request.setNote(Constants.REQ_SSOID_NOTE, cookie.getValue());
((HttpRequest) request).setAuthType(entry.authType);
((HttpRequest) request).setUserPrincipal(entry.principal);
} else {
if (debug = 1)
log( No cached principal found, erasing SSO cookie);
cookie.setMaxAge(0);
hres.addCookie(cookie);
}
// Invoke the next Valve in our pipeline
context.invokeNext(request, response);
The only piece of that I'm not doing is the setNote() part; I *think* 
that's only used for the form-based login stuff, but I'm not entirely 
sure-- that's probably the part of the puzzle I still don't 
understand. The basic authenicator doesn't seem to use it.

Scott

At 3:10 PM -0400 6/11/03, Tim Funk wrote:
I don't have time to see whats wrong, but check the 
SingleSignOnValve as a reference to compare your code.

-Tim

Scott Kelley wrote:
We've had an Apache/Tomcat configuration deployed for a couple 
years now. Authentication is handled by a custom Apache plugin 
written in C. Everything works great and has been quite reliable.

Now we would like to move to a standalone Tomcat configuration and 
have been investigating writing a Valve/Authenticator to replace 
our existing Apache plugin.

I've written a prototype Valve and it does almost everything we 
need. This gives us the ability to require a server-wide login 
independent of how the individual servlet contexts are configured. 
This ends up being Tomcat-specific, but we're ok with that.

The only problem with the current prototype is that if a user hits 
a servlet or JSP in a Context that's configured for basic 
authentication, they still get the browser-generated basic login 
dialog, even after being logged in with our Valve.

In my code, I check for a particular cookie, and if I find it, I 
set the user principal in the request to the appropriate user, 
something like this:

// Has connection already been authenticated
// (i.e. do we have the login cookie?)
Cookie lcookie=ValveUtils.findCookie(hreq,LOGIN_COOKIE_NAME);
// If the request has the login cookie, let it pass through
if (lcookie!=null) {
log(Found login cookie, validating);
if (validLoginCookie(lcookie,hreq)) {
log(cookie is valid, allowing request);
// See AuthenticatorBase.invoke(), which also sets 
authType and userPrincipal
// See SignleSignOn.invoke(), which also set authType 
and userPrincipal
hrequest.getRequest().setUserPrincipal(new 
TempPrincipal(bob_temp_user));
hrequest.getRequest().setAuthType(BASIC);
context.invokeNext(request,response);
} else {
log(cookie not valid, going to error page);
hres.sendRedirect(hres.encodeRedirectURL(ERROR_PAGE_URI));
}
return;
}

I had thought that this would work, because later in the pipeline 
the request hits BasicAuthenticator, which does this:

public boolean authenticate(HttpRequest request,
HttpResponse response,
LoginConfig config)
throws IOException {
// Have we already authenticated someone?
Principal principal =
((HttpServletRequest) request.getRequest()).getUserPrincipal();
if (principal != null) {
if (debug = 1)
log(Already authenticated ' + principal.getName() + ');
return (true);
}
And since I've set the principal to something besides null, I had 
assumed that the basic authentication would just be skipped. Which 
is not the behavior that I'm seeing. Instead, I end up asking the 
user to log in twice: once for my custom Valve (which is a web 
form/redirect thing), and a second time when they hit a servlet in 
a context with basic authentication (which causes the browser to 
put up the basic authentication dialog).

So, what am I missing?

Thanks,

Scott
-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


Re: Valve as Custom Authenticator

2003-06-11 Thread Scott Kelley
Aha, you're right!

First problem, I didn't have the right logging enabled; I hadn't 
noticed that I didn't see any of the log messages from 
BasicAuthenticator.java.

Second problem, with logging cranked up appropriately, is that 
BasicAuthenticator gets called before my code.

Which leads to my next question: how can I get called before 
BasicAuthenticator?

I had the Valve installed as the first item in the Engine; when it's 
there it apparently gets called after BasicAuthenticator. I tried 
moving my valve up a level into the Service, but my code didn't seem 
to get called at all when I installed the valve there.

Let me ask a related question: If I have a valve that's setting the 
principal and authType, do I need to set a Realm in server.xml, and 
if so, what should I set it to? Do I need to write a Realm that 
somehow talks to my Valve (since the request info isn't available in 
Tomcat 4)? This is, I think, the piece of the puzzle that I don't 
completely understand.

Scott

At 5:03 PM -0400 6/11/03, Tim Funk wrote:
I took a little longer look. All looks ok to me. Turn up 
debugging. Are you sure that your valve is being executed before the 
BasicAuthenticator valve?

-Tim

Scott Kelley wrote:
SingleSignOn has much the same code as BasicAuthenticator:

in org.apache.catalina.authenticator.SingleSignOn.java:

// Look up the cached Principal associated with this cookie value
if (debug = 1)
log( Checking for cached principal for  + cookie.getValue());
SingleSignOnEntry entry = lookup(cookie.getValue());
if (entry != null) {
if (debug = 1)
log( Found cached principal ' +
entry.principal.getName() + ' with auth type ' +
entry.authType + ');
request.setNote(Constants.REQ_SSOID_NOTE, cookie.getValue());
((HttpRequest) request).setAuthType(entry.authType);
((HttpRequest) request).setUserPrincipal(entry.principal);
} else {
if (debug = 1)
log( No cached principal found, erasing SSO cookie);
cookie.setMaxAge(0);
hres.addCookie(cookie);
}
// Invoke the next Valve in our pipeline
context.invokeNext(request, response);
The only piece of that I'm not doing is the setNote() part; I 
*think* that's only used for the form-based login stuff, but I'm 
not entirely sure-- that's probably the part of the puzzle I still 
don't understand. The basic authenicator doesn't seem to use it.

Scott

At 3:10 PM -0400 6/11/03, Tim Funk wrote:

I don't have time to see whats wrong, but check the 
SingleSignOnValve as a reference to compare your code.

-Tim

Scott Kelley wrote:

We've had an Apache/Tomcat configuration deployed for a couple 
years now. Authentication is handled by a custom Apache plugin 
written in C. Everything works great and has been quite reliable.

Now we would like to move to a standalone Tomcat configuration 
and have been investigating writing a Valve/Authenticator to 
replace our existing Apache plugin.

I've written a prototype Valve and it does almost everything we 
need. This gives us the ability to require a server-wide login 
independent of how the individual servlet contexts are 
configured. This ends up being Tomcat-specific, but we're ok with 
that.

The only problem with the current prototype is that if a user 
hits a servlet or JSP in a Context that's configured for basic 
authentication, they still get the browser-generated basic login 
dialog, even after being logged in with our Valve.

In my code, I check for a particular cookie, and if I find it, I 
set the user principal in the request to the appropriate user, 
something like this:

// Has connection already been authenticated
// (i.e. do we have the login cookie?)
Cookie lcookie=ValveUtils.findCookie(hreq,LOGIN_COOKIE_NAME);
// If the request has the login cookie, let it pass through
if (lcookie!=null) {
log(Found login cookie, validating);
if (validLoginCookie(lcookie,hreq)) {
log(cookie is valid, allowing request);
// See AuthenticatorBase.invoke(), which also sets 
authType and userPrincipal
// See SignleSignOn.invoke(), which also set authType 
and userPrincipal
hrequest.getRequest().setUserPrincipal(new 
TempPrincipal(bob_temp_user));
hrequest.getRequest().setAuthType(BASIC);
context.invokeNext(request,response);
} else {
log(cookie not valid, going to error page);
hres.sendRedirect(hres.encodeRedirectURL(ERROR_PAGE_URI));
}
return;
}

I had thought that this would work, because later in the pipeline 
the request hits BasicAuthenticator, which does this:

public boolean authenticate(HttpRequest request,
HttpResponse response,
LoginConfig config)
throws IOException

Changing *Default* allowLinking Behavior

2003-01-29 Thread Scott Kelley
Hi Tomcat Users,

I'm having a problem with one of my server configurations (which has 
come up repeatedly on this list) where various items in my servlet 
contexts are unix symbolic links (on Solaris, RedHat, or MacOS X), 
and since Tomcat 4.1.18 by default disallows following these symlinks 
for security reasons, the configuration no longer works under 4.1.18. 
Previously we ran this way with Tomcat 4.0.x and 3.x with no 
problems, but the symlink behavior apparently changed in 4.1.x.

The solution (which has also come up repeatedly on the list) is 
apparently to use the allowLinking flag, like this:

Context  ... some valid context ... 

Resources className=org.apache.naming.resources.FileDirContext
 allowLinking=true /

/Context

Now this is all well and good, and I'm pretty sure it will solve our problem.

It only has one drawback... we have many servlet contexts, and we 
have never bothered to list them all in server.xml; we just let the 
default context apply to everything.

So, is there a way to configure server.xml such that the *default* 
behavior will be allowLinking=true, or do we have to manually list 
every servlet context in server.xml?

From reading the documentation, I thought that something like this might work:

Engine name=Standalone defaultHost=localhost debug=0

DefaultContext

Resources className=org.apache.naming.resources.FileDirContext
 allowLinking=true /

/DefaultContext

/Engine

but I tried it and it didn't seem to work using 4.1.18. Also, I 
couldn't find any mention of this on the list; does anybody use a 
configuration like this?

Oh, and in case anyone's curious, the configuration we use with all 
the symlinks is one of our development configurations; our deployment 
builds do not use symlinks at all, so the problem (and the security 
issue) doesn't come up.

Any tips appreciated.

Thanks,

Scott Kelley

P.S. No, we don't want to change the default value in 
FileDirContext.java and recompile tomcat, but thanks for the 
suggestion! :-)


-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



Adding security constraints on a per-server basis

2001-04-25 Thread Scott Kelley

Hi,

I'm using Tomcat 3.2.1 on Solaris.

Is it possible to add a security-constraint tag somewhere so that 
it will apply to the entire server at once? I want to lock down my 
whole development server at once, instead of having to write separate 
web.xml files for each application.

I tried adding a security constraint to the web.xml file in Tomcat's 
conf/web.xml file, in the hope that adding to the default servlet 
would make it apply to all servlets, but it didn't seem to work. Is 
it supposed to? If this does work, does anyone have an example?

Thanks,

Scott
-- 
--
Scott Kelley, [EMAIL PROTECTED]
Biology Computing Services, UC San Diego
--



Importing OpenSSL Private Key with keytool

2001-03-09 Thread Scott Kelley

Is it simply impossible to import a private key from openssl into a 
keystore using keytool?

And, if so... then am I missing something? Doesn't this make it 
impossible to use Tomcat's built-in SSL support with anything other 
than a self-signed key, or a key generated by keytool itself?

If it's not impossible, can somebody please explain to me how to do it?

If it is impossible, is this a limitation of keytool, or the 
java.security API? Could I do it with a short piece of code?

Thanks,

Scott




--
Scott Kelley, [EMAIL PROTECTED]
Biology Computing Services, UC San Diego
--

-
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, email: [EMAIL PROTECTED]