2
* Licensed to the Apache Software Foundation (ASF) under one or more
3
* contributor license agreements. See the NOTICE file distributed with
4
* this work for additional information regarding copyright ownership.
5
* The ASF licenses this file to You under the Apache License, Version 2.0
6
* (the "License"); you may not use this file except in compliance with
7
* the License. You may obtain a copy of the License at
9
* http://www.apache.org/licenses/LICENSE-2.0
11
* Unless required by applicable law or agreed to in writing, software
12
* distributed under the License is distributed on an "AS IS" BASIS,
13
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
* See the License for the specific language governing permissions and
15
* limitations under the License.
19
package org.apache.catalina.authenticator;
22
import java.io.IOException;
23
import java.security.Principal;
25
import javax.servlet.http.HttpServletResponse;
27
import org.apache.catalina.connector.Request;
28
import org.apache.catalina.connector.Response;
29
import org.apache.catalina.deploy.LoginConfig;
30
import org.apache.catalina.util.Base64;
31
import org.apache.juli.logging.Log;
32
import org.apache.juli.logging.LogFactory;
33
import org.apache.tomcat.util.buf.ByteChunk;
34
import org.apache.tomcat.util.buf.CharChunk;
35
import org.apache.tomcat.util.buf.MessageBytes;
40
* An <b>Authenticator</b> and <b>Valve</b> implementation of HTTP BASIC
41
* Authentication, as outlined in RFC 2617: "HTTP Authentication: Basic
42
* and Digest Access Authentication."
44
* @author Craig R. McClanahan
45
* @version $Revision: 467222 $ $Date: 2006-10-24 05:17:11 +0200 (Di, 24. Okt 2006) $
48
public class BasicAuthenticator
49
extends AuthenticatorBase {
50
private static Log log = LogFactory.getLog(BasicAuthenticator.class);
57
public static final byte[] AUTHENTICATE_BYTES = {
77
// ----------------------------------------------------- Instance Variables
81
* Descriptive information about this implementation.
83
protected static final String info =
84
"org.apache.catalina.authenticator.BasicAuthenticator/1.0";
87
// ------------------------------------------------------------- Properties
91
* Return descriptive information about this Valve implementation.
93
public String getInfo() {
100
// --------------------------------------------------------- Public Methods
104
* Authenticate the user making this request, based on the specified
105
* login configuration. Return <code>true</code> if any specified
106
* constraint has been satisfied, or <code>false</code> if we have
107
* created a response challenge already.
109
* @param request Request we are processing
110
* @param response Response we are creating
111
* @param config Login configuration describing how authentication
112
* should be performed
114
* @exception IOException if an input/output error occurs
116
public boolean authenticate(Request request,
121
// Have we already authenticated someone?
122
Principal principal = request.getUserPrincipal();
123
String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
124
if (principal != null) {
125
if (log.isDebugEnabled())
126
log.debug("Already authenticated '" + principal.getName() + "'");
127
// Associate the session with any existing SSO session
129
associate(ssoId, request.getSessionInternal(true));
133
// Is there an SSO session against which we can try to reauthenticate?
135
if (log.isDebugEnabled())
136
log.debug("SSO Id " + ssoId + " set; attempting " +
138
/* Try to reauthenticate using data cached by SSO. If this fails,
139
either the original SSO logon was of DIGEST or SSL (which
140
we can't reauthenticate ourselves because there is no
141
cached username and password), or the realm denied
142
the user's reauthentication for some reason.
143
In either case we have to prompt the user for a logon */
144
if (reauthenticateFromSSO(ssoId, request))
148
// Validate any credentials already included with this request
149
String username = null;
150
String password = null;
152
MessageBytes authorization =
153
request.getCoyoteRequest().getMimeHeaders()
154
.getValue("authorization");
156
if (authorization != null) {
157
authorization.toBytes();
158
ByteChunk authorizationBC = authorization.getByteChunk();
159
if (authorizationBC.startsWithIgnoreCase("basic ", 0)) {
160
authorizationBC.setOffset(authorizationBC.getOffset() + 6);
161
// FIXME: Add trimming
162
// authorizationBC.trim();
164
CharChunk authorizationCC = authorization.getCharChunk();
165
Base64.decode(authorizationBC, authorizationCC);
167
// Get username and password
168
int colon = authorizationCC.indexOf(':');
170
username = authorizationCC.toString();
172
char[] buf = authorizationCC.getBuffer();
173
username = new String(buf, 0, colon);
174
password = new String(buf, colon + 1,
175
authorizationCC.getEnd() - colon - 1);
178
authorizationBC.setOffset(authorizationBC.getOffset() - 6);
181
principal = context.getRealm().authenticate(username, password);
182
if (principal != null) {
183
register(request, response, principal, Constants.BASIC_METHOD,
190
// Send an "unauthorized" response and an appropriate challenge
191
MessageBytes authenticate =
192
response.getCoyoteResponse().getMimeHeaders()
193
.addValue(AUTHENTICATE_BYTES, 0, AUTHENTICATE_BYTES.length);
194
CharChunk authenticateCC = authenticate.getCharChunk();
195
authenticateCC.append("Basic realm=\"");
196
if (config.getRealmName() == null) {
197
authenticateCC.append(request.getServerName());
198
authenticateCC.append(':');
199
authenticateCC.append(Integer.toString(request.getServerPort()));
201
authenticateCC.append(config.getRealmName());
203
authenticateCC.append('\"');
204
authenticate.toChars();
205
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
206
//response.flushBuffer();