init
This commit is contained in:
487
java/org/apache/catalina/realm/CombinedRealm.java
Normal file
487
java/org/apache/catalina/realm/CombinedRealm.java
Normal file
@@ -0,0 +1,487 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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 org.apache.catalina.realm;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.apache.catalina.Container;
|
||||
import org.apache.catalina.Lifecycle;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.Realm;
|
||||
import org.apache.catalina.Wrapper;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.ietf.jgss.GSSContext;
|
||||
import org.ietf.jgss.GSSCredential;
|
||||
import org.ietf.jgss.GSSException;
|
||||
import org.ietf.jgss.GSSName;
|
||||
|
||||
/**
|
||||
* Realm implementation that contains one or more realms. Authentication is
|
||||
* attempted for each realm in the order they were configured. If any realm
|
||||
* authenticates the user then the authentication succeeds. When combining
|
||||
* realms usernames should be unique across all combined realms.
|
||||
*/
|
||||
public class CombinedRealm extends RealmBase {
|
||||
|
||||
private static final Log log = LogFactory.getLog(CombinedRealm.class);
|
||||
|
||||
/**
|
||||
* The list of Realms contained by this Realm.
|
||||
*/
|
||||
protected final List<Realm> realms = new LinkedList<>();
|
||||
|
||||
/**
|
||||
* Descriptive information about this Realm implementation.
|
||||
* @deprecated This will be removed in Tomcat 9 onwards.
|
||||
*/
|
||||
@Deprecated
|
||||
protected static final String name = "CombinedRealm";
|
||||
|
||||
/**
|
||||
* Add a realm to the list of realms that will be used to authenticate
|
||||
* users.
|
||||
* @param theRealm realm which should be wrapped by the combined realm
|
||||
*/
|
||||
public void addRealm(Realm theRealm) {
|
||||
realms.add(theRealm);
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
sm.getString("combinedRealm.addRealm",
|
||||
theRealm.getClass().getName(),
|
||||
Integer.toString(realms.size()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the set of Realms that this Realm is wrapping
|
||||
*/
|
||||
public ObjectName[] getRealms() {
|
||||
ObjectName[] result = new ObjectName[realms.size()];
|
||||
for (Realm realm : realms) {
|
||||
if (realm instanceof RealmBase) {
|
||||
result[realms.indexOf(realm)] =
|
||||
((RealmBase) realm).getObjectName();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the list of Realms contained by this Realm.
|
||||
*/
|
||||
public Realm[] getNestedRealms() {
|
||||
return realms.toArray(new Realm[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Principal associated with the specified username, which
|
||||
* matches the digest calculated using the given parameters using the
|
||||
* method described in RFC 2069; otherwise return <code>null</code>.
|
||||
*
|
||||
* @param username Username of the Principal to look up
|
||||
* @param clientDigest Digest which has been submitted by the client
|
||||
* @param nonce Unique (or supposedly unique) token which has been used
|
||||
* for this request
|
||||
* @param realmName Realm name
|
||||
* @param md5a2 Second MD5 digest used to calculate the digest :
|
||||
* MD5(Method + ":" + uri)
|
||||
*/
|
||||
@Override
|
||||
public Principal authenticate(String username, String clientDigest,
|
||||
String nonce, String nc, String cnonce, String qop,
|
||||
String realmName, String md5a2) {
|
||||
Principal authenticatedUser = null;
|
||||
|
||||
for (Realm realm : realms) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("combinedRealm.authStart", username,
|
||||
realm.getClass().getName()));
|
||||
}
|
||||
|
||||
authenticatedUser = realm.authenticate(username, clientDigest, nonce,
|
||||
nc, cnonce, qop, realmName, md5a2);
|
||||
|
||||
if (authenticatedUser == null) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("combinedRealm.authFail", username,
|
||||
realm.getClass().getName()));
|
||||
}
|
||||
} else {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("combinedRealm.authSuccess",
|
||||
username, realm.getClass().getName()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return authenticatedUser;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the Principal associated with the specified user name otherwise
|
||||
* return <code>null</code>.
|
||||
*
|
||||
* @param username User name of the Principal to look up
|
||||
*/
|
||||
@Override
|
||||
public Principal authenticate(String username) {
|
||||
Principal authenticatedUser = null;
|
||||
|
||||
for (Realm realm : realms) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("combinedRealm.authStart", username,
|
||||
realm.getClass().getName()));
|
||||
}
|
||||
|
||||
authenticatedUser = realm.authenticate(username);
|
||||
|
||||
if (authenticatedUser == null) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("combinedRealm.authFail", username,
|
||||
realm.getClass().getName()));
|
||||
}
|
||||
} else {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("combinedRealm.authSuccess",
|
||||
username, realm.getClass().getName()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return authenticatedUser;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the Principal associated with the specified username and
|
||||
* credentials, if there is one; otherwise return <code>null</code>.
|
||||
*
|
||||
* @param username Username of the Principal to look up
|
||||
* @param credentials Password or other credentials to use in
|
||||
* authenticating this username
|
||||
*/
|
||||
@Override
|
||||
public Principal authenticate(String username, String credentials) {
|
||||
Principal authenticatedUser = null;
|
||||
|
||||
for (Realm realm : realms) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("combinedRealm.authStart", username,
|
||||
realm.getClass().getName()));
|
||||
}
|
||||
|
||||
authenticatedUser = realm.authenticate(username, credentials);
|
||||
|
||||
if (authenticatedUser == null) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("combinedRealm.authFail", username,
|
||||
realm.getClass().getName()));
|
||||
}
|
||||
} else {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("combinedRealm.authSuccess",
|
||||
username, realm.getClass().getName()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return authenticatedUser;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the Container with which this Realm has been associated.
|
||||
*
|
||||
* @param container The associated Container
|
||||
*/
|
||||
@Override
|
||||
public void setContainer(Container container) {
|
||||
for(Realm realm : realms) {
|
||||
// Set the realmPath for JMX naming
|
||||
if (realm instanceof RealmBase) {
|
||||
((RealmBase) realm).setRealmPath(
|
||||
getRealmPath() + "/realm" + realms.indexOf(realm));
|
||||
}
|
||||
|
||||
// Set the container for sub-realms. Mainly so logging works.
|
||||
realm.setContainer(container);
|
||||
}
|
||||
super.setContainer(container);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepare for the beginning of active use of the public methods of this
|
||||
* component and implement the requirements of
|
||||
* {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
|
||||
*
|
||||
* @exception LifecycleException if this component detects a fatal error
|
||||
* that prevents this component from being used
|
||||
*/
|
||||
@Override
|
||||
protected void startInternal() throws LifecycleException {
|
||||
// Start 'sub-realms' then this one
|
||||
Iterator<Realm> iter = realms.iterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
Realm realm = iter.next();
|
||||
if (realm instanceof Lifecycle) {
|
||||
try {
|
||||
((Lifecycle) realm).start();
|
||||
} catch (LifecycleException e) {
|
||||
// If realm doesn't start can't authenticate against it
|
||||
iter.remove();
|
||||
log.error(sm.getString("combinedRealm.realmStartFail",
|
||||
realm.getClass().getName()), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
super.startInternal();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gracefully terminate the active use of the public methods of this
|
||||
* component and implement the requirements of
|
||||
* {@link org.apache.catalina.util.LifecycleBase#stopInternal()}.
|
||||
*
|
||||
* @exception LifecycleException if this component detects a fatal error
|
||||
* that needs to be reported
|
||||
*/
|
||||
@Override
|
||||
protected void stopInternal() throws LifecycleException {
|
||||
// Stop this realm, then the sub-realms (reverse order to start)
|
||||
super.stopInternal();
|
||||
for (Realm realm : realms) {
|
||||
if (realm instanceof Lifecycle) {
|
||||
((Lifecycle) realm).stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ensure child Realms are destroyed when this Realm is destroyed.
|
||||
*/
|
||||
@Override
|
||||
protected void destroyInternal() throws LifecycleException {
|
||||
for (Realm realm : realms) {
|
||||
if (realm instanceof Lifecycle) {
|
||||
((Lifecycle) realm).destroy();
|
||||
}
|
||||
}
|
||||
super.destroyInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate the backgroundProcess call to all sub-realms.
|
||||
*/
|
||||
@Override
|
||||
public void backgroundProcess() {
|
||||
super.backgroundProcess();
|
||||
|
||||
for (Realm r : realms) {
|
||||
r.backgroundProcess();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Principal associated with the specified chain of X509
|
||||
* client certificates. If there is none, return <code>null</code>.
|
||||
*
|
||||
* @param certs Array of client certificates, with the first one in
|
||||
* the array being the certificate of the client itself.
|
||||
*/
|
||||
@Override
|
||||
public Principal authenticate(X509Certificate[] certs) {
|
||||
Principal authenticatedUser = null;
|
||||
String username = null;
|
||||
if (certs != null && certs.length >0) {
|
||||
username = certs[0].getSubjectDN().getName();
|
||||
}
|
||||
|
||||
for (Realm realm : realms) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("combinedRealm.authStart", username,
|
||||
realm.getClass().getName()));
|
||||
}
|
||||
|
||||
authenticatedUser = realm.authenticate(certs);
|
||||
|
||||
if (authenticatedUser == null) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("combinedRealm.authFail", username,
|
||||
realm.getClass().getName()));
|
||||
}
|
||||
} else {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("combinedRealm.authSuccess",
|
||||
username, realm.getClass().getName()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return authenticatedUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Principal authenticate(GSSContext gssContext, boolean storeCred) {
|
||||
if (gssContext.isEstablished()) {
|
||||
Principal authenticatedUser = null;
|
||||
GSSName gssName = null;
|
||||
try {
|
||||
gssName = gssContext.getSrcName();
|
||||
} catch (GSSException e) {
|
||||
log.warn(sm.getString("realmBase.gssNameFail"), e);
|
||||
return null;
|
||||
}
|
||||
|
||||
for (Realm realm : realms) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("combinedRealm.authStart",
|
||||
gssName, realm.getClass().getName()));
|
||||
}
|
||||
|
||||
authenticatedUser = realm.authenticate(gssContext, storeCred);
|
||||
|
||||
if (authenticatedUser == null) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("combinedRealm.authFail",
|
||||
gssName, realm.getClass().getName()));
|
||||
}
|
||||
} else {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("combinedRealm.authSuccess",
|
||||
gssName, realm.getClass().getName()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return authenticatedUser;
|
||||
}
|
||||
|
||||
// Fail in all other cases
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public Principal authenticate(GSSName gssName, GSSCredential gssCredential) {
|
||||
Principal authenticatedUser = null;
|
||||
|
||||
for (Realm realm : realms) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("combinedRealm.authStart",
|
||||
gssName, realm.getClass().getName()));
|
||||
}
|
||||
|
||||
if (!(realm instanceof org.apache.catalina.GSSRealm)) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("combinedRealm.authFail",
|
||||
gssName, realm.getClass().getName()));
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
authenticatedUser = ((org.apache.catalina.GSSRealm) realm).authenticate(gssName, gssCredential);
|
||||
|
||||
if (authenticatedUser == null) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("combinedRealm.authFail",
|
||||
gssName, realm.getClass().getName()));
|
||||
}
|
||||
} else {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("combinedRealm.authSuccess",
|
||||
gssName, realm.getClass().getName()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return authenticatedUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean hasRole(Wrapper wrapper, Principal principal, String role) {
|
||||
for (Realm realm : realms) {
|
||||
if (realm.hasRole(wrapper, principal, role)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
protected String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPassword(String username) {
|
||||
// This method should never be called
|
||||
// Stack trace will show where this was called from
|
||||
UnsupportedOperationException uoe =
|
||||
new UnsupportedOperationException(
|
||||
sm.getString("combinedRealm.getPassword"));
|
||||
log.error(sm.getString("combinedRealm.unexpectedMethod"), uoe);
|
||||
throw uoe;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Principal getPrincipal(String username) {
|
||||
// This method should never be called
|
||||
// Stack trace will show where this was called from
|
||||
UnsupportedOperationException uoe =
|
||||
new UnsupportedOperationException(
|
||||
sm.getString("combinedRealm.getPrincipal"));
|
||||
log.error(sm.getString("combinedRealm.unexpectedMethod"), uoe);
|
||||
throw uoe;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
for (Realm realm : realms) {
|
||||
if (!realm.isAvailable()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
42
java/org/apache/catalina/realm/Constants.java
Normal file
42
java/org/apache/catalina/realm/Constants.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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 org.apache.catalina.realm;
|
||||
|
||||
/**
|
||||
* Manifest constants for this Java package.
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
*
|
||||
* @deprecated Unused. Will be removed in Tomcat 9
|
||||
*/
|
||||
@Deprecated
|
||||
public final class Constants {
|
||||
|
||||
public static final String Package = "org.apache.catalina.realm";
|
||||
|
||||
// Authentication methods for login configuration
|
||||
public static final String FORM_METHOD = "FORM";
|
||||
|
||||
// Form based authentication constants
|
||||
public static final String FORM_ACTION = "/j_security_check";
|
||||
|
||||
// User data constraints for transport guarantee
|
||||
public static final String NONE_TRANSPORT = "NONE";
|
||||
public static final String INTEGRAL_TRANSPORT = "INTEGRAL";
|
||||
public static final String CONFIDENTIAL_TRANSPORT = "CONFIDENTIAL";
|
||||
|
||||
}
|
||||
587
java/org/apache/catalina/realm/DataSourceRealm.java
Normal file
587
java/org/apache/catalina/realm/DataSourceRealm.java
Normal file
@@ -0,0 +1,587 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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 org.apache.catalina.realm;
|
||||
|
||||
|
||||
import java.security.Principal;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.naming.ContextBindings;
|
||||
|
||||
/**
|
||||
*
|
||||
* Implementation of <b>Realm</b> that works with any JDBC JNDI DataSource.
|
||||
* See the JDBCRealm.howto for more details on how to set up the database and
|
||||
* for configuration options.
|
||||
*
|
||||
* @author Glenn L. Nielsen
|
||||
* @author Craig R. McClanahan
|
||||
* @author Carson McDonald
|
||||
* @author Ignacio Ortega
|
||||
*/
|
||||
public class DataSourceRealm extends RealmBase {
|
||||
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
|
||||
/**
|
||||
* The generated string for the roles PreparedStatement
|
||||
*/
|
||||
private String preparedRoles = null;
|
||||
|
||||
|
||||
/**
|
||||
* The generated string for the credentials PreparedStatement
|
||||
*/
|
||||
private String preparedCredentials = null;
|
||||
|
||||
|
||||
/**
|
||||
* The name of the JNDI JDBC DataSource
|
||||
*/
|
||||
protected String dataSourceName = null;
|
||||
|
||||
|
||||
/**
|
||||
* Context local datasource.
|
||||
*/
|
||||
protected boolean localDataSource = false;
|
||||
|
||||
|
||||
/**
|
||||
* Descriptive information about this Realm implementation.
|
||||
* @deprecated This will be removed in Tomcat 9 onwards.
|
||||
*/
|
||||
@Deprecated
|
||||
protected static final String name = "DataSourceRealm";
|
||||
|
||||
|
||||
/**
|
||||
* The column in the user role table that names a role
|
||||
*/
|
||||
protected String roleNameCol = null;
|
||||
|
||||
|
||||
/**
|
||||
* The column in the user table that holds the user's credentials
|
||||
*/
|
||||
protected String userCredCol = null;
|
||||
|
||||
|
||||
/**
|
||||
* The column in the user table that holds the user's name
|
||||
*/
|
||||
protected String userNameCol = null;
|
||||
|
||||
|
||||
/**
|
||||
* The table that holds the relation between user's and roles
|
||||
*/
|
||||
protected String userRoleTable = null;
|
||||
|
||||
|
||||
/**
|
||||
* The table that holds user data.
|
||||
*/
|
||||
protected String userTable = null;
|
||||
|
||||
|
||||
/**
|
||||
* Last connection attempt.
|
||||
*/
|
||||
private volatile boolean connectionSuccess = true;
|
||||
|
||||
|
||||
// ------------------------------------------------------------- Properties
|
||||
|
||||
|
||||
/**
|
||||
* @return the name of the JNDI JDBC DataSource.
|
||||
*/
|
||||
public String getDataSourceName() {
|
||||
return dataSourceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the JNDI JDBC DataSource.
|
||||
*
|
||||
* @param dataSourceName the name of the JNDI JDBC DataSource
|
||||
*/
|
||||
public void setDataSourceName( String dataSourceName) {
|
||||
this.dataSourceName = dataSourceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if the datasource will be looked up in the webapp JNDI Context.
|
||||
*/
|
||||
public boolean getLocalDataSource() {
|
||||
return localDataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to cause the datasource to be looked up in the webapp JNDI
|
||||
* Context.
|
||||
*
|
||||
* @param localDataSource the new flag value
|
||||
*/
|
||||
public void setLocalDataSource(boolean localDataSource) {
|
||||
this.localDataSource = localDataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the column in the user role table that names a role.
|
||||
*/
|
||||
public String getRoleNameCol() {
|
||||
return roleNameCol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the column in the user role table that names a role.
|
||||
*
|
||||
* @param roleNameCol The column name
|
||||
*/
|
||||
public void setRoleNameCol( String roleNameCol ) {
|
||||
this.roleNameCol = roleNameCol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the column in the user table that holds the user's credentials.
|
||||
*/
|
||||
public String getUserCredCol() {
|
||||
return userCredCol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the column in the user table that holds the user's credentials.
|
||||
*
|
||||
* @param userCredCol The column name
|
||||
*/
|
||||
public void setUserCredCol( String userCredCol ) {
|
||||
this.userCredCol = userCredCol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the column in the user table that holds the user's name.
|
||||
*/
|
||||
public String getUserNameCol() {
|
||||
return userNameCol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the column in the user table that holds the user's name.
|
||||
*
|
||||
* @param userNameCol The column name
|
||||
*/
|
||||
public void setUserNameCol( String userNameCol ) {
|
||||
this.userNameCol = userNameCol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the table that holds the relation between user's and roles.
|
||||
*/
|
||||
public String getUserRoleTable() {
|
||||
return userRoleTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the table that holds the relation between user's and roles.
|
||||
*
|
||||
* @param userRoleTable The table name
|
||||
*/
|
||||
public void setUserRoleTable( String userRoleTable ) {
|
||||
this.userRoleTable = userRoleTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the table that holds user data..
|
||||
*/
|
||||
public String getUserTable() {
|
||||
return userTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the table that holds user data.
|
||||
*
|
||||
* @param userTable The table name
|
||||
*/
|
||||
public void setUserTable( String userTable ) {
|
||||
this.userTable = userTable;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
/**
|
||||
* Return the Principal associated with the specified username and
|
||||
* credentials, if there is one; otherwise return <code>null</code>.
|
||||
*
|
||||
* If there are any errors with the JDBC connection, executing
|
||||
* the query or anything we return null (don't authenticate). This
|
||||
* event is also logged, and the connection will be closed so that
|
||||
* a subsequent request will automatically re-open it.
|
||||
*
|
||||
* @param username Username of the Principal to look up
|
||||
* @param credentials Password or other credentials to use in
|
||||
* authenticating this username
|
||||
* @return the associated principal, or <code>null</code> if there is none.
|
||||
*/
|
||||
@Override
|
||||
public Principal authenticate(String username, String credentials) {
|
||||
|
||||
// No user or no credentials
|
||||
// Can't possibly authenticate, don't bother the database then
|
||||
if (username == null || credentials == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Connection dbConnection = null;
|
||||
|
||||
// Ensure that we have an open database connection
|
||||
dbConnection = open();
|
||||
if (dbConnection == null) {
|
||||
// If the db connection open fails, return "not authenticated"
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Acquire a Principal object for this user
|
||||
return authenticate(dbConnection, username, credentials);
|
||||
}
|
||||
finally
|
||||
{
|
||||
close(dbConnection);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return connectionSuccess;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------- Package Methods
|
||||
|
||||
|
||||
// ------------------------------------------------------ Protected Methods
|
||||
|
||||
|
||||
/**
|
||||
* Return the Principal associated with the specified username and
|
||||
* credentials, if there is one; otherwise return <code>null</code>.
|
||||
*
|
||||
* @param dbConnection The database connection to be used
|
||||
* @param username Username of the Principal to look up
|
||||
* @param credentials Password or other credentials to use in
|
||||
* authenticating this username
|
||||
* @return the associated principal, or <code>null</code> if there is none.
|
||||
*/
|
||||
protected Principal authenticate(Connection dbConnection,
|
||||
String username,
|
||||
String credentials) {
|
||||
// No user or no credentials
|
||||
// Can't possibly authenticate, don't bother the database then
|
||||
if (username == null || credentials == null) {
|
||||
if (containerLog.isTraceEnabled())
|
||||
containerLog.trace(sm.getString("dataSourceRealm.authenticateFailure",
|
||||
username));
|
||||
return null;
|
||||
}
|
||||
|
||||
// Look up the user's credentials
|
||||
String dbCredentials = getPassword(dbConnection, username);
|
||||
|
||||
if(dbCredentials == null) {
|
||||
// User was not found in the database.
|
||||
// Waste a bit of time as not to reveal that the user does not exist.
|
||||
getCredentialHandler().mutate(credentials);
|
||||
|
||||
if (containerLog.isTraceEnabled())
|
||||
containerLog.trace(sm.getString("dataSourceRealm.authenticateFailure",
|
||||
username));
|
||||
return null;
|
||||
}
|
||||
|
||||
// Validate the user's credentials
|
||||
boolean validated = getCredentialHandler().matches(credentials, dbCredentials);
|
||||
|
||||
if (validated) {
|
||||
if (containerLog.isTraceEnabled())
|
||||
containerLog.trace(sm.getString("dataSourceRealm.authenticateSuccess",
|
||||
username));
|
||||
} else {
|
||||
if (containerLog.isTraceEnabled())
|
||||
containerLog.trace(sm.getString("dataSourceRealm.authenticateFailure",
|
||||
username));
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList<String> list = getRoles(dbConnection, username);
|
||||
|
||||
// Create and return a suitable Principal for this user
|
||||
return new GenericPrincipal(username, credentials, list);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Close the specified database connection.
|
||||
*
|
||||
* @param dbConnection The connection to be closed
|
||||
*/
|
||||
protected void close(Connection dbConnection) {
|
||||
|
||||
// Do nothing if the database connection is already closed
|
||||
if (dbConnection == null)
|
||||
return;
|
||||
|
||||
// Commit if not auto committed
|
||||
try {
|
||||
if (!dbConnection.getAutoCommit()) {
|
||||
dbConnection.commit();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
containerLog.error("Exception committing connection before closing:", e);
|
||||
}
|
||||
|
||||
// Close this database connection, and log any errors
|
||||
try {
|
||||
dbConnection.close();
|
||||
} catch (SQLException e) {
|
||||
containerLog.error(sm.getString("dataSourceRealm.close"), e); // Just log it here
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the specified database connection.
|
||||
*
|
||||
* @return Connection to the database
|
||||
*/
|
||||
protected Connection open() {
|
||||
|
||||
try {
|
||||
Context context = null;
|
||||
if (localDataSource) {
|
||||
context = ContextBindings.getClassLoader();
|
||||
context = (Context) context.lookup("comp/env");
|
||||
} else {
|
||||
context = getServer().getGlobalNamingContext();
|
||||
}
|
||||
DataSource dataSource = (DataSource)context.lookup(dataSourceName);
|
||||
Connection connection = dataSource.getConnection();
|
||||
connectionSuccess = true;
|
||||
return connection;
|
||||
} catch (Exception e) {
|
||||
connectionSuccess = false;
|
||||
// Log the problem for posterity
|
||||
containerLog.error(sm.getString("dataSourceRealm.exception"), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
protected String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the password associated with the given principal's user name.
|
||||
*/
|
||||
@Override
|
||||
protected String getPassword(String username) {
|
||||
|
||||
Connection dbConnection = null;
|
||||
|
||||
// Ensure that we have an open database connection
|
||||
dbConnection = open();
|
||||
if (dbConnection == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return getPassword(dbConnection, username);
|
||||
} finally {
|
||||
close(dbConnection);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the password associated with the given principal's user name.
|
||||
*
|
||||
* @param dbConnection The database connection to be used
|
||||
* @param username Username for which password should be retrieved
|
||||
*
|
||||
* @return the password for the specified user
|
||||
*/
|
||||
protected String getPassword(Connection dbConnection, String username) {
|
||||
|
||||
String dbCredentials = null;
|
||||
|
||||
try (PreparedStatement stmt = dbConnection.prepareStatement(preparedCredentials)) {
|
||||
stmt.setString(1, username);
|
||||
|
||||
try (ResultSet rs = stmt.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
dbCredentials = rs.getString(1);
|
||||
}
|
||||
|
||||
return (dbCredentials != null) ? dbCredentials.trim() : null;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
containerLog.error(sm.getString("dataSourceRealm.getPassword.exception", username), e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the Principal associated with the given user name.
|
||||
* @param username the user name
|
||||
* @return the principal object
|
||||
*/
|
||||
@Override
|
||||
protected Principal getPrincipal(String username) {
|
||||
Connection dbConnection = open();
|
||||
if (dbConnection == null) {
|
||||
return new GenericPrincipal(username, null, null);
|
||||
}
|
||||
try {
|
||||
return new GenericPrincipal(username,
|
||||
getPassword(dbConnection, username),
|
||||
getRoles(dbConnection, username));
|
||||
} finally {
|
||||
close(dbConnection);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the roles associated with the given user name.
|
||||
* @param username User name for which roles should be retrieved
|
||||
* @return an array list of the role names
|
||||
*/
|
||||
protected ArrayList<String> getRoles(String username) {
|
||||
|
||||
Connection dbConnection = null;
|
||||
|
||||
// Ensure that we have an open database connection
|
||||
dbConnection = open();
|
||||
if (dbConnection == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return getRoles(dbConnection, username);
|
||||
} finally {
|
||||
close(dbConnection);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the roles associated with the given user name.
|
||||
*
|
||||
* @param dbConnection The database connection to be used
|
||||
* @param username User name for which roles should be retrieved
|
||||
*
|
||||
* @return an array list of the role names
|
||||
*/
|
||||
protected ArrayList<String> getRoles(Connection dbConnection, String username) {
|
||||
|
||||
if (allRolesMode != AllRolesMode.STRICT_MODE && !isRoleStoreDefined()) {
|
||||
// Using an authentication only configuration and no role store has
|
||||
// been defined so don't spend cycles looking
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList<String> list = null;
|
||||
|
||||
try (PreparedStatement stmt = dbConnection.prepareStatement(preparedRoles)) {
|
||||
stmt.setString(1, username);
|
||||
|
||||
try (ResultSet rs = stmt.executeQuery()) {
|
||||
list = new ArrayList<>();
|
||||
|
||||
while (rs.next()) {
|
||||
String role = rs.getString(1);
|
||||
if (role != null) {
|
||||
list.add(role.trim());
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
} catch(SQLException e) {
|
||||
containerLog.error(sm.getString("dataSourceRealm.getRoles.exception", username), e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private boolean isRoleStoreDefined() {
|
||||
return userRoleTable != null || roleNameCol != null;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------ Lifecycle Methods
|
||||
|
||||
/**
|
||||
* Prepare for the beginning of active use of the public methods of this
|
||||
* component and implement the requirements of
|
||||
* {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
|
||||
*
|
||||
* @exception LifecycleException if this component detects a fatal error
|
||||
* that prevents this component from being used
|
||||
*/
|
||||
@Override
|
||||
protected void startInternal() throws LifecycleException {
|
||||
|
||||
// Create the roles PreparedStatement string
|
||||
StringBuilder temp = new StringBuilder("SELECT ");
|
||||
temp.append(roleNameCol);
|
||||
temp.append(" FROM ");
|
||||
temp.append(userRoleTable);
|
||||
temp.append(" WHERE ");
|
||||
temp.append(userNameCol);
|
||||
temp.append(" = ?");
|
||||
preparedRoles = temp.toString();
|
||||
|
||||
// Create the credentials PreparedStatement string
|
||||
temp = new StringBuilder("SELECT ");
|
||||
temp.append(userCredCol);
|
||||
temp.append(" FROM ");
|
||||
temp.append(userTable);
|
||||
temp.append(" WHERE ");
|
||||
temp.append(userNameCol);
|
||||
temp.append(" = ?");
|
||||
preparedCredentials = temp.toString();
|
||||
|
||||
super.startInternal();
|
||||
}
|
||||
}
|
||||
295
java/org/apache/catalina/realm/DigestCredentialHandlerBase.java
Normal file
295
java/org/apache/catalina/realm/DigestCredentialHandlerBase.java
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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 org.apache.catalina.realm;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Random;
|
||||
|
||||
import org.apache.catalina.CredentialHandler;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.tomcat.util.buf.HexUtils;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* Base implementation for the Tomcat provided {@link CredentialHandler}s.
|
||||
*/
|
||||
public abstract class DigestCredentialHandlerBase implements CredentialHandler {
|
||||
|
||||
protected static final StringManager sm =
|
||||
StringManager.getManager(DigestCredentialHandlerBase.class);
|
||||
|
||||
public static final int DEFAULT_SALT_LENGTH = 32;
|
||||
|
||||
private int iterations = getDefaultIterations();
|
||||
private int saltLength = getDefaultSaltLength();
|
||||
private final Object randomLock = new Object();
|
||||
private volatile Random random = null;
|
||||
private boolean logInvalidStoredCredentials = false;
|
||||
|
||||
|
||||
/**
|
||||
* @return the number of iterations of the associated algorithm that will be
|
||||
* used when creating a new stored credential for a given input credential.
|
||||
*/
|
||||
public int getIterations() {
|
||||
return iterations;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the number of iterations of the associated algorithm that will be
|
||||
* used when creating a new stored credential for a given input credential.
|
||||
* @param iterations the iterations count
|
||||
*/
|
||||
public void setIterations(int iterations) {
|
||||
this.iterations = iterations;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the salt length that will be used when creating a new stored
|
||||
* credential for a given input credential.
|
||||
*/
|
||||
public int getSaltLength() {
|
||||
return saltLength;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the salt length that will be used when creating a new stored
|
||||
* credential for a given input credential.
|
||||
* @param saltLength the salt length
|
||||
*/
|
||||
public void setSaltLength(int saltLength) {
|
||||
this.saltLength = saltLength;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* When checking input credentials against stored credentials will a warning
|
||||
* message be logged if invalid stored credentials are discovered?
|
||||
* @return <code>true</code> if logging will occur
|
||||
*/
|
||||
public boolean getLogInvalidStoredCredentials() {
|
||||
return logInvalidStoredCredentials;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set whether a warning message will be logged if invalid stored
|
||||
* credentials are discovered while checking input credentials against
|
||||
* stored credentials?
|
||||
* @param logInvalidStoredCredentials <code>true</code> to log, the
|
||||
* default value is <code>false</code>
|
||||
*/
|
||||
public void setLogInvalidStoredCredentials(boolean logInvalidStoredCredentials) {
|
||||
this.logInvalidStoredCredentials = logInvalidStoredCredentials;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String mutate(String userCredential) {
|
||||
byte[] salt = null;
|
||||
int iterations = getIterations();
|
||||
int saltLength = getSaltLength();
|
||||
if (saltLength == 0) {
|
||||
salt = new byte[0];
|
||||
} else if (saltLength > 0) {
|
||||
// Double checked locking. OK since random is volatile.
|
||||
if (random == null) {
|
||||
synchronized (randomLock) {
|
||||
if (random == null) {
|
||||
random = new SecureRandom();
|
||||
}
|
||||
}
|
||||
}
|
||||
salt = new byte[saltLength];
|
||||
// Concurrent use of this random is unlikely to be a performance
|
||||
// issue as it is only used during stored password generation.
|
||||
random.nextBytes(salt);
|
||||
}
|
||||
|
||||
String serverCredential = mutate(userCredential, salt, iterations);
|
||||
|
||||
// Failed to generate server credential from user credential. Points to
|
||||
// a configuration issue. The root cause should have been logged in the
|
||||
// mutate() method.
|
||||
if (serverCredential == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (saltLength == 0 && iterations == 1) {
|
||||
// Output the simple/old format for backwards compatibility
|
||||
return serverCredential;
|
||||
} else {
|
||||
StringBuilder result =
|
||||
new StringBuilder((saltLength << 1) + 10 + serverCredential.length() + 2);
|
||||
result.append(HexUtils.toHexString(salt));
|
||||
result.append('$');
|
||||
result.append(iterations);
|
||||
result.append('$');
|
||||
result.append(serverCredential);
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks whether the provided credential matches the stored credential when
|
||||
* the stored credential is in the form salt$iteration-count$credential
|
||||
*
|
||||
* @param inputCredentials The input credential
|
||||
* @param storedCredentials The stored credential
|
||||
*
|
||||
* @return <code>true</code> if they match, otherwise <code>false</code>
|
||||
*/
|
||||
protected boolean matchesSaltIterationsEncoded(String inputCredentials,
|
||||
String storedCredentials) {
|
||||
|
||||
if (storedCredentials == null) {
|
||||
// Stored credentials are invalid
|
||||
// This may be expected if nested credential handlers are being used
|
||||
logInvalidStoredCredentials(null);
|
||||
return false;
|
||||
}
|
||||
|
||||
int sep1 = storedCredentials.indexOf('$');
|
||||
int sep2 = storedCredentials.indexOf('$', sep1 + 1);
|
||||
|
||||
if (sep1 < 0 || sep2 < 0) {
|
||||
// Stored credentials are invalid
|
||||
// This may be expected if nested credential handlers are being used
|
||||
logInvalidStoredCredentials(storedCredentials);
|
||||
return false;
|
||||
}
|
||||
|
||||
String hexSalt = storedCredentials.substring(0, sep1);
|
||||
|
||||
int iterations = Integer.parseInt(storedCredentials.substring(sep1 + 1, sep2));
|
||||
|
||||
String storedHexEncoded = storedCredentials.substring(sep2 + 1);
|
||||
byte[] salt;
|
||||
try {
|
||||
salt = HexUtils.fromHexString(hexSalt);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
logInvalidStoredCredentials(storedCredentials);
|
||||
return false;
|
||||
}
|
||||
|
||||
String inputHexEncoded = mutate(inputCredentials, salt, iterations,
|
||||
HexUtils.fromHexString(storedHexEncoded).length * Byte.SIZE);
|
||||
if (inputHexEncoded == null) {
|
||||
// Failed to mutate user credentials. Automatic fail.
|
||||
// Root cause should be logged by mutate()
|
||||
return false;
|
||||
}
|
||||
|
||||
return storedHexEncoded.equalsIgnoreCase(inputHexEncoded);
|
||||
}
|
||||
|
||||
|
||||
private void logInvalidStoredCredentials(String storedCredentials) {
|
||||
if (logInvalidStoredCredentials) {
|
||||
// Logging credentials could be a security concern but they are
|
||||
// invalid and that is probably a bigger problem
|
||||
getLog().warn(sm.getString("credentialHandler.invalidStoredCredential",
|
||||
storedCredentials));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the default salt length used by the {@link CredentialHandler}.
|
||||
*/
|
||||
protected int getDefaultSaltLength() {
|
||||
return DEFAULT_SALT_LENGTH;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates the equivalent stored credentials for the given input
|
||||
* credentials, salt and iterations. If the algorithm requires a key length,
|
||||
* the default will be used.
|
||||
*
|
||||
* @param inputCredentials User provided credentials
|
||||
* @param salt Salt, if any
|
||||
* @param iterations Number of iterations of the algorithm associated
|
||||
* with this CredentialHandler applied to the
|
||||
* inputCredentials to generate the equivalent
|
||||
* stored credentials
|
||||
*
|
||||
* @return The equivalent stored credentials for the given input
|
||||
* credentials or <code>null</code> if the generation fails
|
||||
*/
|
||||
protected abstract String mutate(String inputCredentials, byte[] salt, int iterations);
|
||||
|
||||
|
||||
/**
|
||||
* Generates the equivalent stored credentials for the given input
|
||||
* credentials, salt, iterations and key length. The default implementation
|
||||
* calls ignores the key length and calls
|
||||
* {@link #mutate(String, byte[], int)}. Sub-classes that use the key length
|
||||
* should override this method.
|
||||
*
|
||||
* @param inputCredentials User provided credentials
|
||||
* @param salt Salt, if any
|
||||
* @param iterations Number of iterations of the algorithm associated
|
||||
* with this CredentialHandler applied to the
|
||||
* inputCredentials to generate the equivalent
|
||||
* stored credentials
|
||||
* @param keyLength Length of the produced digest in bits for
|
||||
* implementations where it's applicable
|
||||
*
|
||||
* @return The equivalent stored credentials for the given input
|
||||
* credentials or <code>null</code> if the generation fails
|
||||
*/
|
||||
protected String mutate(String inputCredentials, byte[] salt, int iterations, int keyLength) {
|
||||
return mutate(inputCredentials, salt, iterations);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the algorithm used to convert input credentials to stored
|
||||
* credentials.
|
||||
* @param algorithm the algorithm
|
||||
* @throws NoSuchAlgorithmException if the specified algorithm
|
||||
* is not supported
|
||||
*/
|
||||
public abstract void setAlgorithm(String algorithm) throws NoSuchAlgorithmException;
|
||||
|
||||
|
||||
/**
|
||||
* @return the algorithm used to convert input credentials to stored
|
||||
* credentials.
|
||||
*/
|
||||
public abstract String getAlgorithm();
|
||||
|
||||
|
||||
/**
|
||||
* @return the default number of iterations used by the
|
||||
* {@link CredentialHandler}.
|
||||
*/
|
||||
protected abstract int getDefaultIterations();
|
||||
|
||||
|
||||
/**
|
||||
* @return the logger for the CredentialHandler instance.
|
||||
*/
|
||||
protected abstract Log getLog();
|
||||
}
|
||||
281
java/org/apache/catalina/realm/GenericPrincipal.java
Normal file
281
java/org/apache/catalina/realm/GenericPrincipal.java
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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 org.apache.catalina.realm;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.security.Principal;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.security.auth.login.LoginContext;
|
||||
|
||||
import org.apache.catalina.TomcatPrincipal;
|
||||
import org.ietf.jgss.GSSCredential;
|
||||
|
||||
/**
|
||||
* Generic implementation of <strong>java.security.Principal</strong> that
|
||||
* is available for use by <code>Realm</code> implementations.
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
*/
|
||||
public class GenericPrincipal implements TomcatPrincipal, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
// ----------------------------------------------------------- Constructors
|
||||
|
||||
/**
|
||||
* Construct a new Principal, associated with the specified Realm, for the
|
||||
* specified username and password, with the specified role names
|
||||
* (as Strings).
|
||||
*
|
||||
* @param name The username of the user represented by this Principal
|
||||
* @param password Credentials used to authenticate this user
|
||||
* @param roles List of roles (must be Strings) possessed by this user
|
||||
*/
|
||||
public GenericPrincipal(String name, String password, List<String> roles) {
|
||||
this(name, password, roles, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new Principal, associated with the specified Realm, for the
|
||||
* specified username and password, with the specified role names
|
||||
* (as Strings).
|
||||
*
|
||||
* @param name The username of the user represented by this Principal
|
||||
* @param password Credentials used to authenticate this user
|
||||
* @param roles List of roles (must be Strings) possessed by this user
|
||||
* @param userPrincipal - the principal to be returned from the request
|
||||
* getUserPrincipal call if not null; if null, this will be returned
|
||||
*/
|
||||
public GenericPrincipal(String name, String password, List<String> roles,
|
||||
Principal userPrincipal) {
|
||||
this(name, password, roles, userPrincipal, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new Principal, associated with the specified Realm, for the
|
||||
* specified username and password, with the specified role names
|
||||
* (as Strings).
|
||||
*
|
||||
* @param name The username of the user represented by this Principal
|
||||
* @param password Credentials used to authenticate this user
|
||||
* @param roles List of roles (must be Strings) possessed by this user
|
||||
* @param userPrincipal - the principal to be returned from the request
|
||||
* getUserPrincipal call if not null; if null, this will be returned
|
||||
* @param loginContext - If provided, this will be used to log out the user
|
||||
* at the appropriate time
|
||||
*/
|
||||
public GenericPrincipal(String name, String password, List<String> roles,
|
||||
Principal userPrincipal, LoginContext loginContext) {
|
||||
this(name, password, roles, userPrincipal, loginContext, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new Principal, associated with the specified Realm, for the
|
||||
* specified username and password, with the specified role names
|
||||
* (as Strings).
|
||||
*
|
||||
* @param name The username of the user represented by this Principal
|
||||
* @param password Credentials used to authenticate this user
|
||||
* @param roles List of roles (must be Strings) possessed by this user
|
||||
* @param userPrincipal - the principal to be returned from the request
|
||||
* getUserPrincipal call if not null; if null, this will be returned
|
||||
* @param loginContext - If provided, this will be used to log out the user
|
||||
* at the appropriate time
|
||||
* @param gssCredential - If provided, the user's delegated credentials
|
||||
*/
|
||||
public GenericPrincipal(String name, String password, List<String> roles,
|
||||
Principal userPrincipal, LoginContext loginContext,
|
||||
GSSCredential gssCredential) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.password = password;
|
||||
this.userPrincipal = userPrincipal;
|
||||
if (roles == null) {
|
||||
this.roles = new String[0];
|
||||
} else {
|
||||
this.roles = roles.toArray(new String[roles.size()]);
|
||||
if (this.roles.length > 1) {
|
||||
Arrays.sort(this.roles);
|
||||
}
|
||||
}
|
||||
this.loginContext = loginContext;
|
||||
this.gssCredential = gssCredential;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------- Properties
|
||||
|
||||
/**
|
||||
* The username of the user represented by this Principal.
|
||||
*/
|
||||
protected final String name;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The authentication credentials for the user represented by
|
||||
* this Principal.
|
||||
*/
|
||||
protected final String password;
|
||||
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The set of roles associated with this user.
|
||||
*/
|
||||
protected final String roles[];
|
||||
|
||||
public String[] getRoles() {
|
||||
return this.roles;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The authenticated Principal to be exposed to applications.
|
||||
*/
|
||||
protected final Principal userPrincipal;
|
||||
|
||||
@Override
|
||||
public Principal getUserPrincipal() {
|
||||
if (userPrincipal != null) {
|
||||
return userPrincipal;
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The JAAS LoginContext, if any, used to authenticate this Principal.
|
||||
* Kept so we can call logout().
|
||||
*/
|
||||
protected final transient LoginContext loginContext;
|
||||
|
||||
|
||||
/**
|
||||
* The user's delegated credentials.
|
||||
*/
|
||||
protected transient GSSCredential gssCredential = null;
|
||||
|
||||
@Override
|
||||
public GSSCredential getGssCredential() {
|
||||
return this.gssCredential;
|
||||
}
|
||||
protected void setGssCredential(GSSCredential gssCredential) {
|
||||
this.gssCredential = gssCredential;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------- Public Methods
|
||||
|
||||
/**
|
||||
* Does the user represented by this Principal possess the specified role?
|
||||
*
|
||||
* @param role Role to be tested
|
||||
*
|
||||
* @return <code>true</code> if this Principal has been assigned the given
|
||||
* role, otherwise <code>false</code>
|
||||
*/
|
||||
public boolean hasRole(String role) {
|
||||
if ("*".equals(role)) { // Special 2.4 role meaning everyone
|
||||
return true;
|
||||
}
|
||||
if (role == null) {
|
||||
return false;
|
||||
}
|
||||
return Arrays.binarySearch(roles, role) >= 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a String representation of this object, which exposes only
|
||||
* information that should be public.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("GenericPrincipal[");
|
||||
sb.append(this.name);
|
||||
sb.append("(");
|
||||
for (int i = 0; i < roles.length; i++ ) {
|
||||
sb.append( roles[i]).append(",");
|
||||
}
|
||||
sb.append(")]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calls logout, if necessary, on any associated JAASLoginContext. May in
|
||||
* the future be extended to cover other logout requirements.
|
||||
*
|
||||
* @throws Exception If something goes wrong with the logout. Uses Exception
|
||||
* to allow for future expansion of this method to cover
|
||||
* other logout mechanisms that might throw a different
|
||||
* exception to LoginContext
|
||||
*/
|
||||
@Override
|
||||
public void logout() throws Exception {
|
||||
if (loginContext != null) {
|
||||
loginContext.logout();
|
||||
}
|
||||
if (gssCredential != null) {
|
||||
gssCredential.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------- Serialization
|
||||
|
||||
private Object writeReplace() {
|
||||
return new SerializablePrincipal(name, password, roles, userPrincipal);
|
||||
}
|
||||
|
||||
private static class SerializablePrincipal implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String name;
|
||||
private final String password;
|
||||
private final String[] roles;
|
||||
private final Principal principal;
|
||||
|
||||
public SerializablePrincipal(String name, String password, String[] roles,
|
||||
Principal principal) {
|
||||
this.name = name;
|
||||
this.password = password;
|
||||
this.roles = roles;
|
||||
if (principal instanceof Serializable) {
|
||||
this.principal = principal;
|
||||
} else {
|
||||
this.principal = null;
|
||||
}
|
||||
}
|
||||
|
||||
private Object readResolve() {
|
||||
return new GenericPrincipal(name, password, Arrays.asList(roles), principal);
|
||||
}
|
||||
}
|
||||
}
|
||||
227
java/org/apache/catalina/realm/JAASCallbackHandler.java
Normal file
227
java/org/apache/catalina/realm/JAASCallbackHandler.java
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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 org.apache.catalina.realm;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.callback.NameCallback;
|
||||
import javax.security.auth.callback.PasswordCallback;
|
||||
import javax.security.auth.callback.TextInputCallback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* <p>Implementation of the JAAS <code>CallbackHandler</code> interface,
|
||||
* used to negotiate delivery of the username and credentials that were
|
||||
* specified to our constructor. No interaction with the user is required
|
||||
* (or possible).</p>
|
||||
*
|
||||
* <p>This <code>CallbackHandler</code> will pre-digest the supplied
|
||||
* password, if required by the <code><Realm></code> element in
|
||||
* <code>server.xml</code>.</p>
|
||||
* <p>At present, <code>JAASCallbackHandler</code> knows how to handle callbacks of
|
||||
* type <code>javax.security.auth.callback.NameCallback</code> and
|
||||
* <code>javax.security.auth.callback.PasswordCallback</code>.</p>
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
* @author Andrew R. Jaquith
|
||||
*/
|
||||
public class JAASCallbackHandler implements CallbackHandler {
|
||||
|
||||
// ------------------------------------------------------------ Constructor
|
||||
|
||||
|
||||
/**
|
||||
* Construct a callback handler configured with the specified values.
|
||||
* Note that if the <code>JAASRealm</code> instance specifies digested passwords,
|
||||
* the <code>password</code> parameter will be pre-digested here.
|
||||
*
|
||||
* @param realm Our associated JAASRealm instance
|
||||
* @param username Username to be authenticated with
|
||||
* @param password Password to be authenticated with
|
||||
*/
|
||||
public JAASCallbackHandler(JAASRealm realm, String username,
|
||||
String password) {
|
||||
|
||||
this(realm, username, password, null, null, null, null, null, null,
|
||||
null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a callback handler for DIGEST authentication.
|
||||
*
|
||||
* @param realm Our associated JAASRealm instance
|
||||
* @param username Username to be authenticated with
|
||||
* @param password Password to be authenticated with
|
||||
* @param nonce Server generated nonce
|
||||
* @param nc Nonce count
|
||||
* @param cnonce Client generated nonce
|
||||
* @param qop Quality of protection applied to the message
|
||||
* @param realmName Realm name
|
||||
* @param md5a2 Second MD5 digest used to calculate the digest
|
||||
* MD5(Method + ":" + uri)
|
||||
* @param authMethod The authentication method in use
|
||||
*/
|
||||
public JAASCallbackHandler(JAASRealm realm, String username,
|
||||
String password, String nonce, String nc,
|
||||
String cnonce, String qop, String realmName,
|
||||
String md5a2, String authMethod) {
|
||||
this.realm = realm;
|
||||
this.username = username;
|
||||
|
||||
if (realm.hasMessageDigest()) {
|
||||
this.password = realm.getCredentialHandler().mutate(password);
|
||||
}
|
||||
else {
|
||||
this.password = password;
|
||||
}
|
||||
this.nonce = nonce;
|
||||
this.nc = nc;
|
||||
this.cnonce = cnonce;
|
||||
this.qop = qop;
|
||||
this.realmName = realmName;
|
||||
this.md5a2 = md5a2;
|
||||
this.authMethod = authMethod;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
/**
|
||||
* The string manager for this package.
|
||||
*/
|
||||
protected static final StringManager sm = StringManager.getManager(JAASCallbackHandler.class);
|
||||
|
||||
/**
|
||||
* The password to be authenticated with.
|
||||
*/
|
||||
protected final String password;
|
||||
|
||||
|
||||
/**
|
||||
* The associated <code>JAASRealm</code> instance.
|
||||
*/
|
||||
protected final JAASRealm realm;
|
||||
|
||||
/**
|
||||
* The username to be authenticated with.
|
||||
*/
|
||||
protected final String username;
|
||||
|
||||
/**
|
||||
* Server generated nonce.
|
||||
*/
|
||||
protected final String nonce;
|
||||
|
||||
/**
|
||||
* Nonce count.
|
||||
*/
|
||||
protected final String nc;
|
||||
|
||||
/**
|
||||
* Client generated nonce.
|
||||
*/
|
||||
protected final String cnonce;
|
||||
|
||||
/**
|
||||
* Quality of protection applied to the message.
|
||||
*/
|
||||
protected final String qop;
|
||||
|
||||
/**
|
||||
* Realm name.
|
||||
*/
|
||||
protected final String realmName;
|
||||
|
||||
/**
|
||||
* Second MD5 digest.
|
||||
*/
|
||||
protected final String md5a2;
|
||||
|
||||
/**
|
||||
* The authentication method to be used. If null, assume BASIC/FORM.
|
||||
*/
|
||||
protected final String authMethod;
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the information requested in the provided <code>Callbacks</code>.
|
||||
* This implementation only recognizes {@link NameCallback},
|
||||
* {@link PasswordCallback} and {@link TextInputCallback}.
|
||||
* {@link TextInputCallback} is used to pass the various additional
|
||||
* parameters required for DIGEST authentication.
|
||||
*
|
||||
* @param callbacks The set of <code>Callback</code>s to be processed
|
||||
*
|
||||
* @exception IOException if an input/output error occurs
|
||||
* @exception UnsupportedCallbackException if the login method requests
|
||||
* an unsupported callback type
|
||||
*/
|
||||
@Override
|
||||
public void handle(Callback callbacks[])
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
|
||||
for (int i = 0; i < callbacks.length; i++) {
|
||||
|
||||
if (callbacks[i] instanceof NameCallback) {
|
||||
if (realm.getContainer().getLogger().isTraceEnabled())
|
||||
realm.getContainer().getLogger().trace(sm.getString("jaasCallback.username", username));
|
||||
((NameCallback) callbacks[i]).setName(username);
|
||||
} else if (callbacks[i] instanceof PasswordCallback) {
|
||||
final char[] passwordcontents;
|
||||
if (password != null) {
|
||||
passwordcontents = password.toCharArray();
|
||||
} else {
|
||||
passwordcontents = new char[0];
|
||||
}
|
||||
((PasswordCallback) callbacks[i]).setPassword
|
||||
(passwordcontents);
|
||||
} else if (callbacks[i] instanceof TextInputCallback) {
|
||||
TextInputCallback cb = ((TextInputCallback) callbacks[i]);
|
||||
if (cb.getPrompt().equals("nonce")) {
|
||||
cb.setText(nonce);
|
||||
} else if (cb.getPrompt().equals("nc")) {
|
||||
cb.setText(nc);
|
||||
} else if (cb.getPrompt().equals("cnonce")) {
|
||||
cb.setText(cnonce);
|
||||
} else if (cb.getPrompt().equals("qop")) {
|
||||
cb.setText(qop);
|
||||
} else if (cb.getPrompt().equals("realmName")) {
|
||||
cb.setText(realmName);
|
||||
} else if (cb.getPrompt().equals("md5a2")) {
|
||||
cb.setText(md5a2);
|
||||
} else if (cb.getPrompt().equals("authMethod")) {
|
||||
cb.setText(authMethod);
|
||||
} else if (cb.getPrompt().equals("catalinaBase")) {
|
||||
cb.setText(realm.getContainer().getCatalinaBase().getAbsolutePath());
|
||||
} else {
|
||||
throw new UnsupportedCallbackException(callbacks[i]);
|
||||
}
|
||||
} else {
|
||||
throw new UnsupportedCallbackException(callbacks[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
432
java/org/apache/catalina/realm/JAASMemoryLoginModule.java
Normal file
432
java/org/apache/catalina/realm/JAASMemoryLoginModule.java
Normal file
@@ -0,0 +1,432 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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 org.apache.catalina.realm;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.Principal;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.callback.NameCallback;
|
||||
import javax.security.auth.callback.PasswordCallback;
|
||||
import javax.security.auth.callback.TextInputCallback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
import javax.security.auth.login.FailedLoginException;
|
||||
import javax.security.auth.login.LoginException;
|
||||
import javax.security.auth.spi.LoginModule;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.catalina.CredentialHandler;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.IntrospectionUtils;
|
||||
import org.apache.tomcat.util.digester.Digester;
|
||||
|
||||
/**
|
||||
* <p>Implementation of the JAAS <strong>LoginModule</strong> interface,
|
||||
* primarily for use in testing <code>JAASRealm</code>. It utilizes an
|
||||
* XML-format data file of username/password/role information identical to
|
||||
* that supported by <code>org.apache.catalina.realm.MemoryRealm</code>.</p>
|
||||
*
|
||||
* <p>This class recognizes the following string-valued options, which are
|
||||
* specified in the configuration file and passed to {@link
|
||||
* #initialize(Subject, CallbackHandler, Map, Map)} in the <code>options</code>
|
||||
* argument:</p>
|
||||
* <ul>
|
||||
* <li><strong>pathname</strong> - Relative (to the pathname specified by the
|
||||
* "catalina.base" system property) or absolute pathname to the
|
||||
* XML file containing our user information, in the format supported by
|
||||
* {@link MemoryRealm}. The default value matches the MemoryRealm
|
||||
* default.</li>
|
||||
* <li><strong>credentialHandlerClassName</strong> - The fully qualified class
|
||||
* name of the CredentialHandler to use. If not specified, {@link
|
||||
* MessageDigestCredentialHandler} will be used.</li>
|
||||
* <li>Any additional options will be used to identify and call setters on the
|
||||
* {@link CredentialHandler}. For example, <code>algorithm=SHA256</code>
|
||||
* would result in a call to {@link
|
||||
* MessageDigestCredentialHandler#setAlgorithm(String)} with a parameter of
|
||||
* <code>"SHA256"</code></li>
|
||||
* </ul>
|
||||
*
|
||||
* <p><strong>IMPLEMENTATION NOTE</strong> - This class implements
|
||||
* <code>Realm</code> only to satisfy the calling requirements of the
|
||||
* <code>GenericPrincipal</code> constructor. It does not actually perform
|
||||
* the functionality required of a <code>Realm</code> implementation.</p>
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
*/
|
||||
public class JAASMemoryLoginModule extends MemoryRealm implements LoginModule {
|
||||
// We need to extend MemoryRealm to avoid class cast
|
||||
|
||||
private static final Log log = LogFactory.getLog(JAASMemoryLoginModule.class);
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
|
||||
/**
|
||||
* The callback handler responsible for answering our requests.
|
||||
*/
|
||||
protected CallbackHandler callbackHandler = null;
|
||||
|
||||
|
||||
/**
|
||||
* Has our own <code>commit()</code> returned successfully?
|
||||
*/
|
||||
protected boolean committed = false;
|
||||
|
||||
|
||||
/**
|
||||
* The configuration information for this <code>LoginModule</code>.
|
||||
*/
|
||||
protected Map<String,?> options = null;
|
||||
|
||||
|
||||
/**
|
||||
* The absolute or relative pathname to the XML configuration file.
|
||||
*/
|
||||
protected String pathname = "conf/tomcat-users.xml";
|
||||
|
||||
|
||||
/**
|
||||
* The <code>Principal</code> identified by our validation, or
|
||||
* <code>null</code> if validation failed.
|
||||
*/
|
||||
protected Principal principal = null;
|
||||
|
||||
|
||||
/**
|
||||
* The state information that is shared with other configured
|
||||
* <code>LoginModule</code> instances.
|
||||
*/
|
||||
protected Map<String,?> sharedState = null;
|
||||
|
||||
|
||||
/**
|
||||
* The subject for which we are performing authentication.
|
||||
*/
|
||||
protected Subject subject = null;
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
public JAASMemoryLoginModule() {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("MEMORY LOGIN MODULE");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Phase 2 of authenticating a <code>Subject</code> when Phase 1
|
||||
* fails. This method is called if the <code>LoginContext</code>
|
||||
* failed somewhere in the overall authentication chain.
|
||||
*
|
||||
* @return <code>true</code> if this method succeeded, or
|
||||
* <code>false</code> if this <code>LoginModule</code> should be
|
||||
* ignored
|
||||
*
|
||||
* @exception LoginException if the abort fails
|
||||
*/
|
||||
@Override
|
||||
public boolean abort() throws LoginException {
|
||||
|
||||
// If our authentication was not successful, just return false
|
||||
if (principal == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clean up if overall authentication failed
|
||||
if (committed) {
|
||||
logout();
|
||||
} else {
|
||||
committed = false;
|
||||
principal = null;
|
||||
}
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Abort");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Phase 2 of authenticating a <code>Subject</code> when Phase 1
|
||||
* was successful. This method is called if the <code>LoginContext</code>
|
||||
* succeeded in the overall authentication chain.
|
||||
*
|
||||
* @return <code>true</code> if the authentication succeeded, or
|
||||
* <code>false</code> if this <code>LoginModule</code> should be
|
||||
* ignored
|
||||
*
|
||||
* @exception LoginException if the commit fails
|
||||
*/
|
||||
@Override
|
||||
public boolean commit() throws LoginException {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("commit " + principal);
|
||||
}
|
||||
|
||||
// If authentication was not successful, just return false
|
||||
if (principal == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add our Principal to the Subject if needed
|
||||
if (!subject.getPrincipals().contains(principal)) {
|
||||
subject.getPrincipals().add(principal);
|
||||
// Add the roles as additional subjects as per the contract with the
|
||||
// JAASRealm
|
||||
if (principal instanceof GenericPrincipal) {
|
||||
String roles[] = ((GenericPrincipal) principal).getRoles();
|
||||
for (int i = 0; i < roles.length; i++) {
|
||||
subject.getPrincipals().add(new GenericPrincipal(roles[i], null, null));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
committed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize this <code>LoginModule</code> with the specified
|
||||
* configuration information.
|
||||
*
|
||||
* @param subject The <code>Subject</code> to be authenticated
|
||||
* @param callbackHandler A <code>CallbackHandler</code> for communicating
|
||||
* with the end user as necessary
|
||||
* @param sharedState State information shared with other
|
||||
* <code>LoginModule</code> instances
|
||||
* @param options Configuration information for this specific
|
||||
* <code>LoginModule</code> instance
|
||||
*/
|
||||
@Override
|
||||
public void initialize(Subject subject, CallbackHandler callbackHandler,
|
||||
Map<String,?> sharedState, Map<String,?> options) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Init");
|
||||
}
|
||||
|
||||
// Save configuration values
|
||||
this.subject = subject;
|
||||
this.callbackHandler = callbackHandler;
|
||||
this.sharedState = sharedState;
|
||||
this.options = options;
|
||||
|
||||
// Perform instance-specific initialization
|
||||
Object option = options.get("pathname");
|
||||
if (option instanceof String) {
|
||||
this.pathname = (String) option;
|
||||
}
|
||||
|
||||
CredentialHandler credentialHandler = null;
|
||||
option = options.get("credentialHandlerClassName");
|
||||
if (option instanceof String) {
|
||||
try {
|
||||
Class<?> clazz = Class.forName((String) option);
|
||||
credentialHandler = (CredentialHandler) clazz.getConstructor().newInstance();
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
if (credentialHandler == null) {
|
||||
credentialHandler = new MessageDigestCredentialHandler();
|
||||
}
|
||||
|
||||
for (Entry<String,?> entry : options.entrySet()) {
|
||||
if ("pathname".equals(entry.getKey())) {
|
||||
continue;
|
||||
}
|
||||
if ("credentialHandlerClassName".equals(entry.getKey())) {
|
||||
continue;
|
||||
}
|
||||
// Skip any non-String values since any value we are interested in
|
||||
// will be a String.
|
||||
if (entry.getValue() instanceof String) {
|
||||
IntrospectionUtils.setProperty(credentialHandler, entry.getKey(),
|
||||
(String) entry.getValue());
|
||||
}
|
||||
}
|
||||
setCredentialHandler(credentialHandler);
|
||||
|
||||
// Load our defined Principals
|
||||
load();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Phase 1 of authenticating a <code>Subject</code>.
|
||||
*
|
||||
* @return <code>true</code> if the authentication succeeded, or
|
||||
* <code>false</code> if this <code>LoginModule</code> should be
|
||||
* ignored
|
||||
*
|
||||
* @exception LoginException if the authentication fails
|
||||
*/
|
||||
@Override
|
||||
public boolean login() throws LoginException {
|
||||
// Set up our CallbackHandler requests
|
||||
if (callbackHandler == null)
|
||||
throw new LoginException("No CallbackHandler specified");
|
||||
Callback callbacks[] = new Callback[9];
|
||||
callbacks[0] = new NameCallback("Username: ");
|
||||
callbacks[1] = new PasswordCallback("Password: ", false);
|
||||
callbacks[2] = new TextInputCallback("nonce");
|
||||
callbacks[3] = new TextInputCallback("nc");
|
||||
callbacks[4] = new TextInputCallback("cnonce");
|
||||
callbacks[5] = new TextInputCallback("qop");
|
||||
callbacks[6] = new TextInputCallback("realmName");
|
||||
callbacks[7] = new TextInputCallback("md5a2");
|
||||
callbacks[8] = new TextInputCallback("authMethod");
|
||||
|
||||
// Interact with the user to retrieve the username and password
|
||||
String username = null;
|
||||
String password = null;
|
||||
String nonce = null;
|
||||
String nc = null;
|
||||
String cnonce = null;
|
||||
String qop = null;
|
||||
String realmName = null;
|
||||
String md5a2 = null;
|
||||
String authMethod = null;
|
||||
|
||||
try {
|
||||
callbackHandler.handle(callbacks);
|
||||
username = ((NameCallback) callbacks[0]).getName();
|
||||
password =
|
||||
new String(((PasswordCallback) callbacks[1]).getPassword());
|
||||
nonce = ((TextInputCallback) callbacks[2]).getText();
|
||||
nc = ((TextInputCallback) callbacks[3]).getText();
|
||||
cnonce = ((TextInputCallback) callbacks[4]).getText();
|
||||
qop = ((TextInputCallback) callbacks[5]).getText();
|
||||
realmName = ((TextInputCallback) callbacks[6]).getText();
|
||||
md5a2 = ((TextInputCallback) callbacks[7]).getText();
|
||||
authMethod = ((TextInputCallback) callbacks[8]).getText();
|
||||
} catch (IOException | UnsupportedCallbackException e) {
|
||||
throw new LoginException(e.toString());
|
||||
}
|
||||
|
||||
// Validate the username and password we have received
|
||||
if (authMethod == null) {
|
||||
// BASIC or FORM
|
||||
principal = super.authenticate(username, password);
|
||||
} else if (authMethod.equals(HttpServletRequest.DIGEST_AUTH)) {
|
||||
principal = super.authenticate(username, password, nonce, nc,
|
||||
cnonce, qop, realmName, md5a2);
|
||||
} else if (authMethod.equals(HttpServletRequest.CLIENT_CERT_AUTH)) {
|
||||
principal = super.getPrincipal(username);
|
||||
} else {
|
||||
throw new LoginException("Unknown authentication method");
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("login " + username + " " + principal);
|
||||
}
|
||||
|
||||
// Report results based on success or failure
|
||||
if (principal != null) {
|
||||
return true;
|
||||
} else {
|
||||
throw new FailedLoginException("Username or password is incorrect");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log out this user.
|
||||
*
|
||||
* @return <code>true</code> in all cases because the
|
||||
* <code>LoginModule</code> should not be ignored
|
||||
*
|
||||
* @exception LoginException if logging out failed
|
||||
*/
|
||||
@Override
|
||||
public boolean logout() throws LoginException {
|
||||
subject.getPrincipals().remove(principal);
|
||||
committed = false;
|
||||
principal = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------- Realm Methods
|
||||
// ------------------------------------------------------ Protected Methods
|
||||
|
||||
/**
|
||||
* Load the contents of our configuration file.
|
||||
*/
|
||||
protected void load() {
|
||||
// Validate the existence of our configuration file
|
||||
File file = new File(pathname);
|
||||
if (!file.isAbsolute()) {
|
||||
String catalinaBase = getCatalinaBase();
|
||||
if (catalinaBase == null) {
|
||||
log.warn("Unable to determine Catalina base to load file " + pathname);
|
||||
return;
|
||||
} else {
|
||||
file = new File(catalinaBase, pathname);
|
||||
}
|
||||
}
|
||||
if (!file.canRead()) {
|
||||
log.warn("Cannot load configuration file " + file.getAbsolutePath());
|
||||
return;
|
||||
}
|
||||
|
||||
// Load the contents of our configuration file
|
||||
Digester digester = new Digester();
|
||||
digester.setValidating(false);
|
||||
digester.addRuleSet(new MemoryRuleSet());
|
||||
try {
|
||||
digester.push(this);
|
||||
digester.parse(file);
|
||||
} catch (Exception e) {
|
||||
log.warn("Error processing configuration file " + file.getAbsolutePath(), e);
|
||||
return;
|
||||
} finally {
|
||||
digester.reset();
|
||||
}
|
||||
}
|
||||
|
||||
private String getCatalinaBase() {
|
||||
// Have to get this via a callback as that is the only link we have back
|
||||
// to the defining Realm. Can't use the system property as that may not
|
||||
// be set/correct in an embedded scenario
|
||||
|
||||
if (callbackHandler == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Callback callbacks[] = new Callback[1];
|
||||
callbacks[0] = new TextInputCallback("catalinaBase");
|
||||
|
||||
String result = null;
|
||||
|
||||
try {
|
||||
callbackHandler.handle(callbacks);
|
||||
result = ((TextInputCallback) callbacks[0]).getText();
|
||||
} catch (IOException | UnsupportedCallbackException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
697
java/org/apache/catalina/realm/JAASRealm.java
Normal file
697
java/org/apache/catalina/realm/JAASRealm.java
Normal file
@@ -0,0 +1,697 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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 org.apache.catalina.realm;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.security.Principal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.login.AccountExpiredException;
|
||||
import javax.security.auth.login.Configuration;
|
||||
import javax.security.auth.login.CredentialExpiredException;
|
||||
import javax.security.auth.login.FailedLoginException;
|
||||
import javax.security.auth.login.LoginContext;
|
||||
import javax.security.auth.login.LoginException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.catalina.Container;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.ExceptionUtils;
|
||||
|
||||
/**
|
||||
* <p>Implementation of <b>Realm</b> that authenticates users via the <em>Java
|
||||
* Authentication and Authorization Service</em> (JAAS). JAAS support requires
|
||||
* either JDK 1.4 (which includes it as part of the standard platform) or
|
||||
* JDK 1.3 (with the plug-in <code>jaas.jar</code> file).</p>
|
||||
*
|
||||
* <p>The value configured for the <code>appName</code> property is passed to
|
||||
* the <code>javax.security.auth.login.LoginContext</code> constructor, to
|
||||
* specify the <em>application name</em> used to select the set of relevant
|
||||
* <code>LoginModules</code> required.</p>
|
||||
*
|
||||
* <p>The JAAS Specification describes the result of a successful login as a
|
||||
* <code>javax.security.auth.Subject</code> instance, which can contain zero
|
||||
* or more <code>java.security.Principal</code> objects in the return value
|
||||
* of the <code>Subject.getPrincipals()</code> method. However, it provides
|
||||
* no guidance on how to distinguish Principals that describe the individual
|
||||
* user (and are thus appropriate to return as the value of
|
||||
* request.getUserPrincipal() in a web application) from the Principal(s)
|
||||
* that describe the authorized roles for this user. To maintain as much
|
||||
* independence as possible from the underlying <code>LoginMethod</code>
|
||||
* implementation executed by JAAS, the following policy is implemented by
|
||||
* this Realm:</p>
|
||||
* <ul>
|
||||
* <li>The JAAS <code>LoginModule</code> is assumed to return a
|
||||
* <code>Subject</code> with at least one <code>Principal</code> instance
|
||||
* representing the user himself or herself, and zero or more separate
|
||||
* <code>Principals</code> representing the security roles authorized
|
||||
* for this user.</li>
|
||||
* <li>On the <code>Principal</code> representing the user, the Principal
|
||||
* name is an appropriate value to return via the Servlet API method
|
||||
* <code>HttpServletRequest.getRemoteUser()</code>.</li>
|
||||
* <li>On the <code>Principals</code> representing the security roles, the
|
||||
* name is the name of the authorized security role.</li>
|
||||
* <li>This Realm will be configured with two lists of fully qualified Java
|
||||
* class names of classes that implement
|
||||
* <code>java.security.Principal</code> - one that identifies class(es)
|
||||
* representing a user, and one that identifies class(es) representing
|
||||
* a security role.</li>
|
||||
* <li>As this Realm iterates over the <code>Principals</code> returned by
|
||||
* <code>Subject.getPrincipals()</code>, it will identify the first
|
||||
* <code>Principal</code> that matches the "user classes" list as the
|
||||
* <code>Principal</code> for this user.</li>
|
||||
* <li>As this Realm iterates over the <code>Principals</code> returned by
|
||||
* <code>Subject.getPrincipals()</code>, it will accumulate the set of
|
||||
* all <code>Principals</code> matching the "role classes" list as
|
||||
* identifying the security roles for this user.</li>
|
||||
* <li>It is a configuration error for the JAAS login method to return a
|
||||
* validated <code>Subject</code> without a <code>Principal</code> that
|
||||
* matches the "user classes" list.</li>
|
||||
* <li>By default, the enclosing Container's name serves as the
|
||||
* application name used to obtain the JAAS LoginContext ("Catalina" in
|
||||
* a default installation). Tomcat must be able to find an application
|
||||
* with this name in the JAAS configuration file. Here is a hypothetical
|
||||
* JAAS configuration file entry for a database-oriented login module that uses
|
||||
* a Tomcat-managed JNDI database resource:
|
||||
* <blockquote><pre>Catalina {
|
||||
org.foobar.auth.DatabaseLoginModule REQUIRED
|
||||
JNDI_RESOURCE=jdbc/AuthDB
|
||||
USER_TABLE=users
|
||||
USER_ID_COLUMN=id
|
||||
USER_NAME_COLUMN=name
|
||||
USER_CREDENTIAL_COLUMN=password
|
||||
ROLE_TABLE=roles
|
||||
ROLE_NAME_COLUMN=name
|
||||
PRINCIPAL_FACTORY=org.foobar.auth.impl.SimplePrincipalFactory;
|
||||
};</pre></blockquote></li>
|
||||
* <li>To set the JAAS configuration file
|
||||
* location, set the <code>CATALINA_OPTS</code> environment variable
|
||||
* similar to the following:
|
||||
<blockquote><code>CATALINA_OPTS="-Djava.security.auth.login.config=$CATALINA_HOME/conf/jaas.config"</code></blockquote>
|
||||
* </li>
|
||||
* <li>As part of the login process, JAASRealm registers its own <code>CallbackHandler</code>,
|
||||
* called (unsurprisingly) <code>JAASCallbackHandler</code>. This handler supplies the
|
||||
* HTTP requests's username and credentials to the user-supplied <code>LoginModule</code></li>
|
||||
* <li>As with other <code>Realm</code> implementations, digested passwords are supported if
|
||||
* the <code><Realm></code> element in <code>server.xml</code> contains a
|
||||
* <code>digest</code> attribute; <code>JAASCallbackHandler</code> will digest the password
|
||||
* prior to passing it back to the <code>LoginModule</code></li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
* @author Yoav Shapira
|
||||
*/
|
||||
public class JAASRealm extends RealmBase {
|
||||
|
||||
private static final Log log = LogFactory.getLog(JAASRealm.class);
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
|
||||
/**
|
||||
* The application name passed to the JAAS <code>LoginContext</code>,
|
||||
* which uses it to select the set of relevant <code>LoginModule</code>s.
|
||||
*/
|
||||
protected String appName = null;
|
||||
|
||||
|
||||
/**
|
||||
* Descriptive information about this <code>Realm</code> implementation.
|
||||
* @deprecated This will be removed in Tomcat 9 onwards.
|
||||
*/
|
||||
@Deprecated
|
||||
protected static final String name = "JAASRealm";
|
||||
|
||||
|
||||
/**
|
||||
* The list of role class names, split out for easy processing.
|
||||
*/
|
||||
protected final List<String> roleClasses = new ArrayList<>();
|
||||
|
||||
|
||||
/**
|
||||
* The set of user class names, split out for easy processing.
|
||||
*/
|
||||
protected final List<String> userClasses = new ArrayList<>();
|
||||
|
||||
|
||||
/**
|
||||
* Whether to use context ClassLoader or default ClassLoader.
|
||||
* True means use context ClassLoader, and True is the default
|
||||
* value.
|
||||
*/
|
||||
protected boolean useContextClassLoader = true;
|
||||
|
||||
|
||||
/**
|
||||
* Path to find a JAAS configuration file, if not set global JVM JAAS
|
||||
* configuration will be used.
|
||||
*/
|
||||
protected String configFile;
|
||||
|
||||
protected volatile Configuration jaasConfiguration;
|
||||
protected volatile boolean jaasConfigurationLoaded = false;
|
||||
|
||||
/**
|
||||
* Keeps track if JAAS invocation of login modules was successful or not. By
|
||||
* default it is true unless we detect JAAS login module can't perform the
|
||||
* login. This will be used for realm's {@link #isAvailable()} status so
|
||||
* that {@link LockOutRealm} will not lock the user out if JAAS login
|
||||
* modules are unavailable to perform the actual login.
|
||||
*/
|
||||
private volatile boolean invocationSuccess = true;
|
||||
|
||||
// ------------------------------------------------------------- Properties
|
||||
|
||||
/**
|
||||
* @return the path of the JAAS configuration file.
|
||||
*/
|
||||
public String getConfigFile() {
|
||||
return configFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JAAS configuration file.
|
||||
* @param configFile The JAAS configuration file
|
||||
*/
|
||||
public void setConfigFile(String configFile) {
|
||||
this.configFile = configFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JAAS <code>LoginContext</code> app name.
|
||||
* @param name The application name that will be used to retrieve
|
||||
* the set of relevant <code>LoginModule</code>s
|
||||
*/
|
||||
public void setAppName(String name) {
|
||||
appName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the application name.
|
||||
*/
|
||||
public String getAppName() {
|
||||
return appName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to use the context or default ClassLoader.
|
||||
* True means use context ClassLoader.
|
||||
*
|
||||
* @param useContext True means use context ClassLoader
|
||||
*/
|
||||
public void setUseContextClassLoader(boolean useContext) {
|
||||
useContextClassLoader = useContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether to use the context or default ClassLoader.
|
||||
* True means to use the context ClassLoader.
|
||||
*
|
||||
* @return The value of useContextClassLoader
|
||||
*/
|
||||
public boolean isUseContextClassLoader() {
|
||||
return useContextClassLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContainer(Container container) {
|
||||
super.setContainer(container);
|
||||
|
||||
if (appName == null) {
|
||||
appName = makeLegalForJAAS(container.getName());
|
||||
|
||||
log.info("Set JAAS app name " + appName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Comma-delimited list of <code>java.security.Principal</code> classes
|
||||
* that represent security roles.
|
||||
*/
|
||||
protected String roleClassNames = null;
|
||||
|
||||
public String getRoleClassNames() {
|
||||
return this.roleClassNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of comma-delimited classes that represent roles. The
|
||||
* classes in the list must implement <code>java.security.Principal</code>.
|
||||
* The supplied list of classes will be parsed when {@link #start()} is
|
||||
* called.
|
||||
* @param roleClassNames The class names list
|
||||
*/
|
||||
public void setRoleClassNames(String roleClassNames) {
|
||||
this.roleClassNames = roleClassNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a comma-delimited list of class names, and store the class names
|
||||
* in the provided List. Each class must implement
|
||||
* <code>java.security.Principal</code>.
|
||||
*
|
||||
* @param classNamesString a comma-delimited list of fully qualified class names.
|
||||
* @param classNamesList the list in which the class names will be stored.
|
||||
* The list is cleared before being populated.
|
||||
*/
|
||||
protected void parseClassNames(String classNamesString, List<String> classNamesList) {
|
||||
classNamesList.clear();
|
||||
if (classNamesString == null) return;
|
||||
|
||||
ClassLoader loader = this.getClass().getClassLoader();
|
||||
if (isUseContextClassLoader())
|
||||
loader = Thread.currentThread().getContextClassLoader();
|
||||
|
||||
String[] classNames = classNamesString.split("[ ]*,[ ]*");
|
||||
for (int i=0; i<classNames.length; i++) {
|
||||
if (classNames[i].length()==0) continue;
|
||||
try {
|
||||
Class<?> principalClass = Class.forName(classNames[i], false,
|
||||
loader);
|
||||
if (Principal.class.isAssignableFrom(principalClass)) {
|
||||
classNamesList.add(classNames[i]);
|
||||
} else {
|
||||
log.error("Class "+classNames[i]+" is not implementing "+
|
||||
"java.security.Principal! Class not added.");
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
log.error("Class "+classNames[i]+" not found! Class not added.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Comma-delimited list of <code>java.security.Principal</code> classes
|
||||
* that represent individual users.
|
||||
*/
|
||||
protected String userClassNames = null;
|
||||
|
||||
public String getUserClassNames() {
|
||||
return this.userClassNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of comma-delimited classes that represent individual
|
||||
* users. The classes in the list must implement
|
||||
* <code>java.security.Principal</code>. The supplied list of classes will
|
||||
* be parsed when {@link #start()} is called.
|
||||
* @param userClassNames The class names list
|
||||
*/
|
||||
public void setUserClassNames(String userClassNames) {
|
||||
this.userClassNames = userClassNames;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
/**
|
||||
* Return the <code>Principal</code> associated with the specified username
|
||||
* and credentials, if there is one; otherwise return <code>null</code>.
|
||||
*
|
||||
* @param username Username of the <code>Principal</code> to look up
|
||||
* @param credentials Password or other credentials to use in
|
||||
* authenticating this username
|
||||
* @return the associated principal, or <code>null</code> if there is none.
|
||||
*/
|
||||
@Override
|
||||
public Principal authenticate(String username, String credentials) {
|
||||
return authenticate(username,
|
||||
new JAASCallbackHandler(this, username, credentials));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the <code>Principal</code> associated with the specified username
|
||||
* and digest, if there is one; otherwise return <code>null</code>.
|
||||
*
|
||||
* @param username Username of the <code>Principal</code> to look up
|
||||
* @param clientDigest Digest to use in authenticating this username
|
||||
* @param nonce Server generated nonce
|
||||
* @param nc Nonce count
|
||||
* @param cnonce Client generated nonce
|
||||
* @param qop Quality of protection applied to the message
|
||||
* @param realmName Realm name
|
||||
* @param md5a2 Second MD5 digest used to calculate the digest
|
||||
* MD5(Method + ":" + uri)
|
||||
* @return the associated principal, or <code>null</code> if there is none.
|
||||
*/
|
||||
@Override
|
||||
public Principal authenticate(String username, String clientDigest,
|
||||
String nonce, String nc, String cnonce, String qop,
|
||||
String realmName, String md5a2) {
|
||||
return authenticate(username,
|
||||
new JAASCallbackHandler(this, username, clientDigest, nonce,
|
||||
nc, cnonce, qop, realmName, md5a2,
|
||||
HttpServletRequest.DIGEST_AUTH));
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------- Package Methods
|
||||
|
||||
|
||||
// ------------------------------------------------------ Protected Methods
|
||||
|
||||
|
||||
/**
|
||||
* Perform the actual JAAS authentication.
|
||||
* @param username The user name
|
||||
* @param callbackHandler The callback handler
|
||||
* @return the associated principal, or <code>null</code> if there is none.
|
||||
*/
|
||||
protected Principal authenticate(String username,
|
||||
CallbackHandler callbackHandler) {
|
||||
|
||||
// Establish a LoginContext to use for authentication
|
||||
try {
|
||||
LoginContext loginContext = null;
|
||||
if( appName==null ) appName="Tomcat";
|
||||
|
||||
if( log.isDebugEnabled())
|
||||
log.debug(sm.getString("jaasRealm.beginLogin", username, appName));
|
||||
|
||||
// What if the LoginModule is in the container class loader ?
|
||||
ClassLoader ocl = null;
|
||||
|
||||
if (!isUseContextClassLoader()) {
|
||||
ocl = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(
|
||||
this.getClass().getClassLoader());
|
||||
}
|
||||
|
||||
try {
|
||||
Configuration config = getConfig();
|
||||
loginContext = new LoginContext(
|
||||
appName, null, callbackHandler, config);
|
||||
} catch (Throwable e) {
|
||||
ExceptionUtils.handleThrowable(e);
|
||||
log.error(sm.getString("jaasRealm.unexpectedError"), e);
|
||||
// There is configuration issue with JAAS so mark the realm as
|
||||
// unavailable
|
||||
invocationSuccess = false;
|
||||
return null;
|
||||
} finally {
|
||||
if(!isUseContextClassLoader()) {
|
||||
Thread.currentThread().setContextClassLoader(ocl);
|
||||
}
|
||||
}
|
||||
|
||||
if( log.isDebugEnabled())
|
||||
log.debug("Login context created " + username);
|
||||
|
||||
// Negotiate a login via this LoginContext
|
||||
Subject subject = null;
|
||||
try {
|
||||
loginContext.login();
|
||||
subject = loginContext.getSubject();
|
||||
// We were able to perform login successfully so mark JAAS realm as
|
||||
// available as it could have been set to false in prior attempts.
|
||||
// Change invocationSuccess variable only when we know the outcome
|
||||
// of the JAAS operation to keep variable consistent.
|
||||
invocationSuccess = true;
|
||||
if (subject == null) {
|
||||
if( log.isDebugEnabled())
|
||||
log.debug(sm.getString("jaasRealm.failedLogin", username));
|
||||
return (null);
|
||||
}
|
||||
} catch (AccountExpiredException e) {
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("jaasRealm.accountExpired", username));
|
||||
// JAAS checked LoginExceptions are successful authentication
|
||||
// invocations so mark JAAS realm as available
|
||||
invocationSuccess = true;
|
||||
return null;
|
||||
} catch (CredentialExpiredException e) {
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("jaasRealm.credentialExpired", username));
|
||||
// JAAS checked LoginExceptions are successful authentication
|
||||
// invocations so mark JAAS realm as available
|
||||
invocationSuccess = true;
|
||||
return null;
|
||||
} catch (FailedLoginException e) {
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("jaasRealm.failedLogin", username));
|
||||
// JAAS checked LoginExceptions are successful authentication
|
||||
// invocations so mark JAAS realm as available
|
||||
invocationSuccess = true;
|
||||
return null;
|
||||
} catch (LoginException e) {
|
||||
log.warn(sm.getString("jaasRealm.loginException", username), e);
|
||||
// JAAS checked LoginExceptions are successful authentication
|
||||
// invocations so mark JAAS realm as available
|
||||
invocationSuccess = true;
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
ExceptionUtils.handleThrowable(e);
|
||||
log.error(sm.getString("jaasRealm.unexpectedError"), e);
|
||||
// JAAS throws exception different than LoginException so mark the
|
||||
// realm as unavailable
|
||||
invocationSuccess = false;
|
||||
return null;
|
||||
}
|
||||
|
||||
if( log.isDebugEnabled())
|
||||
log.debug(sm.getString("jaasRealm.loginContextCreated", username));
|
||||
|
||||
// Return the appropriate Principal for this authenticated Subject
|
||||
Principal principal = createPrincipal(username, subject, loginContext);
|
||||
if (principal == null) {
|
||||
log.debug(sm.getString("jaasRealm.authenticateFailure", username));
|
||||
return null;
|
||||
}
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("jaasRealm.authenticateSuccess", username));
|
||||
}
|
||||
|
||||
return principal;
|
||||
} catch( Throwable t) {
|
||||
log.error( "error ", t);
|
||||
//JAAS throws exception different than LoginException so mark the realm as unavailable
|
||||
invocationSuccess = false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
protected String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the password associated with the given principal's user name. This
|
||||
* always returns null as the JAASRealm has no way of obtaining this
|
||||
* information.
|
||||
*/
|
||||
@Override
|
||||
protected String getPassword(String username) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the <code>Principal</code> associated with the given user name.
|
||||
*/
|
||||
@Override
|
||||
protected Principal getPrincipal(String username) {
|
||||
|
||||
return authenticate(username,
|
||||
new JAASCallbackHandler(this, username, null, null, null, null,
|
||||
null, null, null, HttpServletRequest.CLIENT_CERT_AUTH));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Identify and return a <code>java.security.Principal</code> instance
|
||||
* representing the authenticated user for the specified <code>Subject</code>.
|
||||
* The Principal is constructed by scanning the list of Principals returned
|
||||
* by the JAASLoginModule. The first <code>Principal</code> object that matches
|
||||
* one of the class names supplied as a "user class" is the user Principal.
|
||||
* This object is returned to the caller.
|
||||
* Any remaining principal objects returned by the LoginModules are mapped to
|
||||
* roles, but only if their respective classes match one of the "role class" classes.
|
||||
* If a user Principal cannot be constructed, return <code>null</code>.
|
||||
* @param username The associated user name
|
||||
* @param subject The <code>Subject</code> representing the logged-in user
|
||||
* @param loginContext Associated with the Principal so
|
||||
* {@link LoginContext#logout()} can be called later
|
||||
* @return the principal object
|
||||
*/
|
||||
protected Principal createPrincipal(String username, Subject subject,
|
||||
LoginContext loginContext) {
|
||||
// Prepare to scan the Principals for this Subject
|
||||
|
||||
List<String> roles = new ArrayList<>();
|
||||
Principal userPrincipal = null;
|
||||
|
||||
// Scan the Principals for this Subject
|
||||
for (Principal principal : subject.getPrincipals()) {
|
||||
String principalClass = principal.getClass().getName();
|
||||
|
||||
if( log.isDebugEnabled() ) {
|
||||
log.debug(sm.getString("jaasRealm.checkPrincipal", principal, principalClass));
|
||||
}
|
||||
|
||||
if (userPrincipal == null && userClasses.contains(principalClass)) {
|
||||
userPrincipal = principal;
|
||||
if( log.isDebugEnabled() ) {
|
||||
log.debug(sm.getString("jaasRealm.userPrincipalSuccess", principal.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
if (roleClasses.contains(principalClass)) {
|
||||
roles.add(principal.getName());
|
||||
if( log.isDebugEnabled() ) {
|
||||
log.debug(sm.getString("jaasRealm.rolePrincipalAdd", principal.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Print failure message if needed
|
||||
if (userPrincipal == null) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("jaasRealm.userPrincipalFailure"));
|
||||
log.debug(sm.getString("jaasRealm.rolePrincipalFailure"));
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
if (roles.size() == 0) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("jaasRealm.rolePrincipalFailure"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the resulting Principal for our authenticated user
|
||||
return new GenericPrincipal(username, null, roles, userPrincipal,
|
||||
loginContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the given name is legal for JAAS configuration.
|
||||
* Added for Bugzilla 30869, made protected for easy customization
|
||||
* in case my implementation is insufficient, which I think is
|
||||
* very likely.
|
||||
*
|
||||
* @param src The name to validate
|
||||
* @return A string that's a valid JAAS realm name
|
||||
*/
|
||||
protected String makeLegalForJAAS(final String src) {
|
||||
String result = src;
|
||||
|
||||
// Default name is "other" per JAAS spec
|
||||
if(result == null) {
|
||||
result = "other";
|
||||
}
|
||||
|
||||
// Strip leading slash if present, as Sun JAAS impl
|
||||
// barfs on it (see Bugzilla 30869 bug report).
|
||||
if(result.startsWith("/")) {
|
||||
result = result.substring(1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------ Lifecycle Methods
|
||||
|
||||
|
||||
/**
|
||||
* Prepare for the beginning of active use of the public methods of this
|
||||
* component and implement the requirements of
|
||||
* {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
|
||||
*
|
||||
* @exception LifecycleException if this component detects a fatal error
|
||||
* that prevents this component from being used
|
||||
*/
|
||||
@Override
|
||||
protected void startInternal() throws LifecycleException {
|
||||
|
||||
// These need to be called after loading configuration, in case
|
||||
// useContextClassLoader appears after them in xml config
|
||||
parseClassNames(userClassNames, userClasses);
|
||||
parseClassNames(roleClassNames, roleClasses);
|
||||
|
||||
super.startInternal();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load custom JAAS Configuration.
|
||||
* @return the loaded configuration
|
||||
*/
|
||||
protected Configuration getConfig() {
|
||||
// Local copy to avoid possible NPE due to concurrent change
|
||||
String configFile = this.configFile;
|
||||
try {
|
||||
if (jaasConfigurationLoaded) {
|
||||
return jaasConfiguration;
|
||||
}
|
||||
synchronized (this) {
|
||||
if (configFile == null) {
|
||||
jaasConfigurationLoaded = true;
|
||||
return null;
|
||||
}
|
||||
URL resource = Thread.currentThread().getContextClassLoader().getResource(configFile);
|
||||
URI uri = resource.toURI();
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<Configuration> sunConfigFile = (Class<Configuration>)
|
||||
Class.forName("com.sun.security.auth.login.ConfigFile");
|
||||
Constructor<Configuration> constructor =
|
||||
sunConfigFile.getConstructor(URI.class);
|
||||
Configuration config = constructor.newInstance(uri);
|
||||
this.jaasConfiguration = config;
|
||||
this.jaasConfigurationLoaded = true;
|
||||
return this.jaasConfiguration;
|
||||
}
|
||||
} catch (URISyntaxException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
} catch (NoSuchMethodException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
} catch (SecurityException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
} catch (InstantiationException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
} catch (IllegalAccessException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
} catch (InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex.getCause());
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return invocationSuccess;
|
||||
}
|
||||
}
|
||||
761
java/org/apache/catalina/realm/JDBCRealm.java
Normal file
761
java/org/apache/catalina/realm/JDBCRealm.java
Normal file
@@ -0,0 +1,761 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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 org.apache.catalina.realm;
|
||||
|
||||
|
||||
import java.security.Principal;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Driver;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.tomcat.util.ExceptionUtils;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Implementation of <b>Realm</b> that works with any JDBC supported database.
|
||||
* See the JDBCRealm.howto for more details on how to set up the database and
|
||||
* for configuration options.
|
||||
*
|
||||
* <p>For a <b>Realm</b> implementation that supports connection pooling and
|
||||
* doesn't require synchronisation of <code>authenticate()</code>,
|
||||
* <code>getPassword()</code>, <code>roles()</code> and
|
||||
* <code>getPrincipal()</code> or the ugly connection logic use the
|
||||
* <code>DataSourceRealm</code>.</p>
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
* @author Carson McDonald
|
||||
* @author Ignacio Ortega
|
||||
*/
|
||||
public class JDBCRealm
|
||||
extends RealmBase {
|
||||
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
|
||||
/**
|
||||
* The connection username to use when trying to connect to the database.
|
||||
*/
|
||||
protected String connectionName = null;
|
||||
|
||||
|
||||
/**
|
||||
* The connection URL to use when trying to connect to the database.
|
||||
*/
|
||||
protected String connectionPassword = null;
|
||||
|
||||
|
||||
/**
|
||||
* The connection URL to use when trying to connect to the database.
|
||||
*/
|
||||
protected String connectionURL = null;
|
||||
|
||||
|
||||
/**
|
||||
* The connection to the database.
|
||||
*/
|
||||
protected Connection dbConnection = null;
|
||||
|
||||
|
||||
/**
|
||||
* Instance of the JDBC Driver class we use as a connection factory.
|
||||
*/
|
||||
protected Driver driver = null;
|
||||
|
||||
|
||||
/**
|
||||
* The JDBC driver to use.
|
||||
*/
|
||||
protected String driverName = null;
|
||||
|
||||
|
||||
/**
|
||||
* Descriptive information about this Realm implementation.
|
||||
* @deprecated This will be removed in Tomcat 9 onwards.
|
||||
*/
|
||||
@Deprecated
|
||||
protected static final String name = "JDBCRealm";
|
||||
|
||||
|
||||
/**
|
||||
* The PreparedStatement to use for authenticating users.
|
||||
*/
|
||||
protected PreparedStatement preparedCredentials = null;
|
||||
|
||||
|
||||
/**
|
||||
* The PreparedStatement to use for identifying the roles for
|
||||
* a specified user.
|
||||
*/
|
||||
protected PreparedStatement preparedRoles = null;
|
||||
|
||||
|
||||
/**
|
||||
* The column in the user role table that names a role
|
||||
*/
|
||||
protected String roleNameCol = null;
|
||||
|
||||
|
||||
/**
|
||||
* The column in the user table that holds the user's credentials
|
||||
*/
|
||||
protected String userCredCol = null;
|
||||
|
||||
|
||||
/**
|
||||
* The column in the user table that holds the user's name
|
||||
*/
|
||||
protected String userNameCol = null;
|
||||
|
||||
|
||||
/**
|
||||
* The table that holds the relation between user's and roles
|
||||
*/
|
||||
protected String userRoleTable = null;
|
||||
|
||||
|
||||
/**
|
||||
* The table that holds user data.
|
||||
*/
|
||||
protected String userTable = null;
|
||||
|
||||
|
||||
// ------------------------------------------------------------- Properties
|
||||
|
||||
/**
|
||||
* @return the username to use to connect to the database.
|
||||
*/
|
||||
public String getConnectionName() {
|
||||
return connectionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the username to use to connect to the database.
|
||||
*
|
||||
* @param connectionName Username
|
||||
*/
|
||||
public void setConnectionName(String connectionName) {
|
||||
this.connectionName = connectionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the password to use to connect to the database.
|
||||
*/
|
||||
public String getConnectionPassword() {
|
||||
return connectionPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the password to use to connect to the database.
|
||||
*
|
||||
* @param connectionPassword User password
|
||||
*/
|
||||
public void setConnectionPassword(String connectionPassword) {
|
||||
this.connectionPassword = connectionPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the URL to use to connect to the database.
|
||||
*/
|
||||
public String getConnectionURL() {
|
||||
return connectionURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URL to use to connect to the database.
|
||||
*
|
||||
* @param connectionURL The new connection URL
|
||||
*/
|
||||
public void setConnectionURL( String connectionURL ) {
|
||||
this.connectionURL = connectionURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the JDBC driver that will be used.
|
||||
*/
|
||||
public String getDriverName() {
|
||||
return driverName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JDBC driver that will be used.
|
||||
*
|
||||
* @param driverName The driver name
|
||||
*/
|
||||
public void setDriverName( String driverName ) {
|
||||
this.driverName = driverName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the column in the user role table that names a role.
|
||||
*/
|
||||
public String getRoleNameCol() {
|
||||
return roleNameCol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the column in the user role table that names a role.
|
||||
*
|
||||
* @param roleNameCol The column name
|
||||
*/
|
||||
public void setRoleNameCol( String roleNameCol ) {
|
||||
this.roleNameCol = roleNameCol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the column in the user table that holds the user's credentials.
|
||||
*/
|
||||
public String getUserCredCol() {
|
||||
return userCredCol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the column in the user table that holds the user's credentials.
|
||||
*
|
||||
* @param userCredCol The column name
|
||||
*/
|
||||
public void setUserCredCol( String userCredCol ) {
|
||||
this.userCredCol = userCredCol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the column in the user table that holds the user's name.
|
||||
*/
|
||||
public String getUserNameCol() {
|
||||
return userNameCol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the column in the user table that holds the user's name.
|
||||
*
|
||||
* @param userNameCol The column name
|
||||
*/
|
||||
public void setUserNameCol( String userNameCol ) {
|
||||
this.userNameCol = userNameCol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the table that holds the relation between user's and roles.
|
||||
*/
|
||||
public String getUserRoleTable() {
|
||||
return userRoleTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the table that holds the relation between user's and roles.
|
||||
*
|
||||
* @param userRoleTable The table name
|
||||
*/
|
||||
public void setUserRoleTable( String userRoleTable ) {
|
||||
this.userRoleTable = userRoleTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the table that holds user data..
|
||||
*/
|
||||
public String getUserTable() {
|
||||
return userTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the table that holds user data.
|
||||
*
|
||||
* @param userTable The table name
|
||||
*/
|
||||
public void setUserTable( String userTable ) {
|
||||
this.userTable = userTable;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
/**
|
||||
* Return the Principal associated with the specified username and
|
||||
* credentials, if there is one; otherwise return <code>null</code>.
|
||||
*
|
||||
* If there are any errors with the JDBC connection, executing
|
||||
* the query or anything we return null (don't authenticate). This
|
||||
* event is also logged, and the connection will be closed so that
|
||||
* a subsequent request will automatically re-open it.
|
||||
*
|
||||
*
|
||||
* @param username Username of the Principal to look up
|
||||
* @param credentials Password or other credentials to use in
|
||||
* authenticating this username
|
||||
* @return the associated principal, or <code>null</code> if there is none.
|
||||
*/
|
||||
@Override
|
||||
public synchronized Principal authenticate(String username, String credentials) {
|
||||
|
||||
// Number of tries is the number of attempts to connect to the database
|
||||
// during this login attempt (if we need to open the database)
|
||||
// This needs rewritten with better pooling support, the existing code
|
||||
// needs signature changes since the Prepared statements needs cached
|
||||
// with the connections.
|
||||
// The code below will try twice if there is an SQLException so the
|
||||
// connection may try to be opened again. On normal conditions (including
|
||||
// invalid login - the above is only used once.
|
||||
int numberOfTries = 2;
|
||||
while (numberOfTries>0) {
|
||||
try {
|
||||
|
||||
// Ensure that we have an open database connection
|
||||
open();
|
||||
|
||||
// Acquire a Principal object for this user
|
||||
Principal principal = authenticate(dbConnection,
|
||||
username, credentials);
|
||||
|
||||
|
||||
// Return the Principal (if any)
|
||||
return principal;
|
||||
|
||||
} catch (SQLException e) {
|
||||
|
||||
// Log the problem for posterity
|
||||
containerLog.error(sm.getString("jdbcRealm.exception"), e);
|
||||
|
||||
// Close the connection so that it gets reopened next time
|
||||
if (dbConnection != null)
|
||||
close(dbConnection);
|
||||
|
||||
}
|
||||
|
||||
numberOfTries--;
|
||||
}
|
||||
|
||||
// Worst case scenario
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------- Package Methods
|
||||
|
||||
|
||||
// ------------------------------------------------------ Protected Methods
|
||||
|
||||
|
||||
/**
|
||||
* Attempt to authenticate the user with the provided credentials.
|
||||
*
|
||||
* @param dbConnection The database connection to be used
|
||||
* @param username Username of the Principal to look up
|
||||
* @param credentials Password or other credentials to use in authenticating
|
||||
* this username
|
||||
*
|
||||
* @return Return the Principal associated with the specified username and
|
||||
* credentials, if there is one; otherwise return <code>null</code>.
|
||||
*/
|
||||
public synchronized Principal authenticate(Connection dbConnection,
|
||||
String username,
|
||||
String credentials) {
|
||||
// No user or no credentials
|
||||
// Can't possibly authenticate, don't bother the database then
|
||||
if (username == null || credentials == null) {
|
||||
if (containerLog.isTraceEnabled())
|
||||
containerLog.trace(sm.getString("jdbcRealm.authenticateFailure",
|
||||
username));
|
||||
return null;
|
||||
}
|
||||
|
||||
// Look up the user's credentials
|
||||
String dbCredentials = getPassword(username);
|
||||
|
||||
if (dbCredentials == null) {
|
||||
// User was not found in the database.
|
||||
// Waste a bit of time as not to reveal that the user does not exist.
|
||||
getCredentialHandler().mutate(credentials);
|
||||
|
||||
if (containerLog.isTraceEnabled())
|
||||
containerLog.trace(sm.getString("jdbcRealm.authenticateFailure",
|
||||
username));
|
||||
return null;
|
||||
}
|
||||
|
||||
// Validate the user's credentials
|
||||
boolean validated = getCredentialHandler().matches(credentials, dbCredentials);
|
||||
|
||||
if (validated) {
|
||||
if (containerLog.isTraceEnabled())
|
||||
containerLog.trace(sm.getString("jdbcRealm.authenticateSuccess",
|
||||
username));
|
||||
} else {
|
||||
if (containerLog.isTraceEnabled())
|
||||
containerLog.trace(sm.getString("jdbcRealm.authenticateFailure",
|
||||
username));
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList<String> roles = getRoles(username);
|
||||
|
||||
// Create and return a suitable Principal for this user
|
||||
return new GenericPrincipal(username, credentials, roles);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return (dbConnection != null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Close the specified database connection.
|
||||
*
|
||||
* @param dbConnection The connection to be closed
|
||||
*/
|
||||
protected void close(Connection dbConnection) {
|
||||
|
||||
// Do nothing if the database connection is already closed
|
||||
if (dbConnection == null)
|
||||
return;
|
||||
|
||||
// Close our prepared statements (if any)
|
||||
try {
|
||||
preparedCredentials.close();
|
||||
} catch (Throwable f) {
|
||||
ExceptionUtils.handleThrowable(f);
|
||||
}
|
||||
this.preparedCredentials = null;
|
||||
|
||||
|
||||
try {
|
||||
preparedRoles.close();
|
||||
} catch (Throwable f) {
|
||||
ExceptionUtils.handleThrowable(f);
|
||||
}
|
||||
this.preparedRoles = null;
|
||||
|
||||
|
||||
// Close this database connection, and log any errors
|
||||
try {
|
||||
dbConnection.close();
|
||||
} catch (SQLException e) {
|
||||
containerLog.warn(sm.getString("jdbcRealm.close"), e); // Just log it here
|
||||
} finally {
|
||||
this.dbConnection = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a PreparedStatement configured to perform the SELECT required
|
||||
* to retrieve user credentials for the specified username.
|
||||
*
|
||||
* @param dbConnection The database connection to be used
|
||||
* @param username Username for which credentials should be retrieved
|
||||
* @return the prepared statement
|
||||
* @exception SQLException if a database error occurs
|
||||
*/
|
||||
protected PreparedStatement credentials(Connection dbConnection,
|
||||
String username)
|
||||
throws SQLException {
|
||||
|
||||
if (preparedCredentials == null) {
|
||||
StringBuilder sb = new StringBuilder("SELECT ");
|
||||
sb.append(userCredCol);
|
||||
sb.append(" FROM ");
|
||||
sb.append(userTable);
|
||||
sb.append(" WHERE ");
|
||||
sb.append(userNameCol);
|
||||
sb.append(" = ?");
|
||||
|
||||
if(containerLog.isDebugEnabled()) {
|
||||
containerLog.debug("credentials query: " + sb.toString());
|
||||
}
|
||||
|
||||
preparedCredentials =
|
||||
dbConnection.prepareStatement(sb.toString());
|
||||
}
|
||||
|
||||
if (username == null) {
|
||||
preparedCredentials.setNull(1,java.sql.Types.VARCHAR);
|
||||
} else {
|
||||
preparedCredentials.setString(1, username);
|
||||
}
|
||||
|
||||
return preparedCredentials;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
protected String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the password for the specified user.
|
||||
* @param username The user name
|
||||
* @return the password associated with the given principal's user name.
|
||||
*/
|
||||
@Override
|
||||
protected synchronized String getPassword(String username) {
|
||||
|
||||
// Look up the user's credentials
|
||||
String dbCredentials = null;
|
||||
|
||||
// Number of tries is the number of attempts to connect to the database
|
||||
// during this login attempt (if we need to open the database)
|
||||
// This needs rewritten with better pooling support, the existing code
|
||||
// needs signature changes since the Prepared statements needs cached
|
||||
// with the connections.
|
||||
// The code below will try twice if there is an SQLException so the
|
||||
// connection may try to be opened again. On normal conditions (including
|
||||
// invalid login - the above is only used once.
|
||||
int numberOfTries = 2;
|
||||
while (numberOfTries > 0) {
|
||||
try {
|
||||
// Ensure that we have an open database connection
|
||||
open();
|
||||
|
||||
PreparedStatement stmt = credentials(dbConnection, username);
|
||||
try (ResultSet rs = stmt.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
dbCredentials = rs.getString(1);
|
||||
}
|
||||
|
||||
dbConnection.commit();
|
||||
|
||||
if (dbCredentials != null) {
|
||||
dbCredentials = dbCredentials.trim();
|
||||
}
|
||||
|
||||
return dbCredentials;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
// Log the problem for posterity
|
||||
containerLog.error(sm.getString("jdbcRealm.exception"), e);
|
||||
}
|
||||
|
||||
// Close the connection so that it gets reopened next time
|
||||
if (dbConnection != null) {
|
||||
close(dbConnection);
|
||||
}
|
||||
|
||||
numberOfTries--;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the principal associated with the specified user.
|
||||
* @param username The user name
|
||||
* @return the Principal associated with the given user name.
|
||||
*/
|
||||
@Override
|
||||
protected synchronized Principal getPrincipal(String username) {
|
||||
|
||||
return new GenericPrincipal(username,
|
||||
getPassword(username),
|
||||
getRoles(username));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the roles associated with the given user name.
|
||||
* @param username The user name
|
||||
* @return an array list of the role names
|
||||
*/
|
||||
protected ArrayList<String> getRoles(String username) {
|
||||
|
||||
if (allRolesMode != AllRolesMode.STRICT_MODE && !isRoleStoreDefined()) {
|
||||
// Using an authentication only configuration and no role store has
|
||||
// been defined so don't spend cycles looking
|
||||
return null;
|
||||
}
|
||||
|
||||
// Number of tries is the number of attempts to connect to the database
|
||||
// during this login attempt (if we need to open the database)
|
||||
// This needs rewritten wuth better pooling support, the existing code
|
||||
// needs signature changes since the Prepared statements needs cached
|
||||
// with the connections.
|
||||
// The code below will try twice if there is an SQLException so the
|
||||
// connection may try to be opened again. On normal conditions (including
|
||||
// invalid login - the above is only used once.
|
||||
int numberOfTries = 2;
|
||||
while (numberOfTries>0) {
|
||||
try {
|
||||
// Ensure that we have an open database connection
|
||||
open();
|
||||
|
||||
PreparedStatement stmt = roles(dbConnection, username);
|
||||
try (ResultSet rs = stmt.executeQuery()) {
|
||||
// Accumulate the user's roles
|
||||
ArrayList<String> roleList = new ArrayList<>();
|
||||
|
||||
while (rs.next()) {
|
||||
String role = rs.getString(1);
|
||||
if (null!=role) {
|
||||
roleList.add(role.trim());
|
||||
}
|
||||
}
|
||||
|
||||
return roleList;
|
||||
} finally {
|
||||
dbConnection.commit();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
// Log the problem for posterity
|
||||
containerLog.error(sm.getString("jdbcRealm.exception"), e);
|
||||
|
||||
// Close the connection so that it gets reopened next time
|
||||
if (dbConnection != null)
|
||||
close(dbConnection);
|
||||
}
|
||||
|
||||
numberOfTries--;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Open (if necessary) and return a database connection for use by
|
||||
* this Realm.
|
||||
* @return the opened connection
|
||||
* @exception SQLException if a database error occurs
|
||||
*/
|
||||
protected Connection open() throws SQLException {
|
||||
|
||||
// Do nothing if there is a database connection already open
|
||||
if (dbConnection != null)
|
||||
return dbConnection;
|
||||
|
||||
// Instantiate our database driver if necessary
|
||||
if (driver == null) {
|
||||
try {
|
||||
Class<?> clazz = Class.forName(driverName);
|
||||
driver = (Driver) clazz.getConstructor().newInstance();
|
||||
} catch (Throwable e) {
|
||||
ExceptionUtils.handleThrowable(e);
|
||||
throw new SQLException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// Open a new connection
|
||||
Properties props = new Properties();
|
||||
if (connectionName != null)
|
||||
props.put("user", connectionName);
|
||||
if (connectionPassword != null)
|
||||
props.put("password", connectionPassword);
|
||||
dbConnection = driver.connect(connectionURL, props);
|
||||
if (dbConnection == null) {
|
||||
throw new SQLException(sm.getString(
|
||||
"jdbcRealm.open.invalidurl",driverName, connectionURL));
|
||||
}
|
||||
dbConnection.setAutoCommit(false);
|
||||
return dbConnection;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a PreparedStatement configured to perform the SELECT required
|
||||
* to retrieve user roles for the specified username.
|
||||
*
|
||||
* @param dbConnection The database connection to be used
|
||||
* @param username Username for which roles should be retrieved
|
||||
* @return the prepared statement
|
||||
* @exception SQLException if a database error occurs
|
||||
*/
|
||||
protected synchronized PreparedStatement roles(Connection dbConnection,
|
||||
String username)
|
||||
throws SQLException {
|
||||
|
||||
if (preparedRoles == null) {
|
||||
StringBuilder sb = new StringBuilder("SELECT ");
|
||||
sb.append(roleNameCol);
|
||||
sb.append(" FROM ");
|
||||
sb.append(userRoleTable);
|
||||
sb.append(" WHERE ");
|
||||
sb.append(userNameCol);
|
||||
sb.append(" = ?");
|
||||
preparedRoles =
|
||||
dbConnection.prepareStatement(sb.toString());
|
||||
}
|
||||
|
||||
preparedRoles.setString(1, username);
|
||||
return preparedRoles;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private boolean isRoleStoreDefined() {
|
||||
return userRoleTable != null || roleNameCol != null;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------ Lifecycle Methods
|
||||
|
||||
/**
|
||||
* Prepare for the beginning of active use of the public methods of this
|
||||
* component and implement the requirements of
|
||||
* {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
|
||||
*
|
||||
* @exception LifecycleException if this component detects a fatal error
|
||||
* that prevents this component from being used
|
||||
*/
|
||||
@Override
|
||||
protected void startInternal() throws LifecycleException {
|
||||
|
||||
// Validate that we can open our connection - but let tomcat
|
||||
// startup in case the database is temporarily unavailable
|
||||
try {
|
||||
open();
|
||||
} catch (SQLException e) {
|
||||
containerLog.error(sm.getString("jdbcRealm.open"), e);
|
||||
}
|
||||
|
||||
super.startInternal();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gracefully terminate the active use of the public methods of this
|
||||
* component and implement the requirements of
|
||||
* {@link org.apache.catalina.util.LifecycleBase#stopInternal()}.
|
||||
*
|
||||
* @exception LifecycleException if this component detects a fatal error
|
||||
* that needs to be reported
|
||||
*/
|
||||
@Override
|
||||
protected void stopInternal() throws LifecycleException {
|
||||
|
||||
super.stopInternal();
|
||||
|
||||
// Close any open DB connection
|
||||
close(this.dbConnection);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
2939
java/org/apache/catalina/realm/JNDIRealm.java
Normal file
2939
java/org/apache/catalina/realm/JNDIRealm.java
Normal file
File diff suppressed because it is too large
Load Diff
103
java/org/apache/catalina/realm/LocalStrings.properties
Normal file
103
java/org/apache/catalina/realm/LocalStrings.properties
Normal file
@@ -0,0 +1,103 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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.
|
||||
|
||||
combinedRealm.addRealm=Add [{0}] realm, making a total of [{1}] realms
|
||||
combinedRealm.authFail=Failed to authenticate user [{0}] with realm [{1}]
|
||||
combinedRealm.authStart=Attempting to authenticate user [{0}] with realm [{1}]
|
||||
combinedRealm.authSuccess=Authenticated user [{0}] with realm [{1}]
|
||||
combinedRealm.getPassword=The getPassword() method should never be called
|
||||
combinedRealm.getPrincipal=The getPrincipal() method should never be called
|
||||
combinedRealm.realmStartFail=Failed to start [{0}] realm
|
||||
combinedRealm.unexpectedMethod=An unexpected call was made to a method on the combined realm
|
||||
|
||||
credentialHandler.invalidStoredCredential=The invalid stored credential string [{0}] was provided by the Realm to match with the user provided credentials
|
||||
|
||||
dataSourceRealm.authenticateFailure=Username [{0}] NOT successfully authenticated
|
||||
dataSourceRealm.authenticateSuccess=Username [{0}] successfully authenticated
|
||||
dataSourceRealm.close=Exception closing database connection
|
||||
dataSourceRealm.exception=Exception performing authentication
|
||||
dataSourceRealm.getPassword.exception=Exception retrieving password for [{0}]
|
||||
dataSourceRealm.getRoles.exception=Exception retrieving roles for [{0}]
|
||||
|
||||
jaasCallback.username=Returned username [{0}]
|
||||
|
||||
jaasRealm.accountExpired=Username [{0}] NOT authenticated due to expired account
|
||||
jaasRealm.authenticateFailure=Username [{0}] NOT successfully authenticated
|
||||
jaasRealm.authenticateSuccess=Username [{0}] successfully authenticated as Principal [{1}] -- Subject was created too
|
||||
jaasRealm.beginLogin=JAASRealm login requested for username [{0}] using LoginContext for application [{1}]
|
||||
jaasRealm.checkPrincipal=Checking Principal [{0}] [{1}]
|
||||
jaasRealm.credentialExpired=Username [{0}] NOT authenticated due to expired credential
|
||||
jaasRealm.failedLogin=Username [{0}] NOT authenticated due to failed login
|
||||
jaasRealm.loginContextCreated=JAAS LoginContext created for username [{0}]
|
||||
jaasRealm.loginException=Login exception authenticating username [{0}]
|
||||
jaasRealm.rolePrincipalAdd=Adding role Principal [{0}] to this user Principal''s roles
|
||||
jaasRealm.rolePrincipalFailure=No valid role Principals found.
|
||||
jaasRealm.unexpectedError=Unexpected error
|
||||
jaasRealm.userPrincipalFailure=No valid user Principal found
|
||||
jaasRealm.userPrincipalSuccess=Principal [{0}] is a valid user class. We will use this as the user Principal.
|
||||
|
||||
jdbcRealm.authenticateFailure=Username [{0}] NOT successfully authenticated
|
||||
jdbcRealm.authenticateSuccess=Username [{0}] successfully authenticated
|
||||
jdbcRealm.close=Exception closing database connection
|
||||
jdbcRealm.exception=Exception performing authentication
|
||||
jdbcRealm.open=Exception opening database connection
|
||||
jdbcRealm.open.invalidurl=Driver [{0}] does not support the url [{1}]
|
||||
|
||||
jndiRealm.authenticateFailure=Username [{0}] NOT successfully authenticated
|
||||
jndiRealm.authenticateSuccess=Username [{0}] successfully authenticated
|
||||
jndiRealm.cipherSuites=Enable [{0}] as cipher suites for tls connection.
|
||||
jndiRealm.close=Exception closing directory server connection
|
||||
jndiRealm.emptyCipherSuites=Empty String for cipher suites given. Using default cipher suites.
|
||||
jndiRealm.exception=Exception performing authentication
|
||||
jndiRealm.exception.retry=Exception performing authentication. Retrying...
|
||||
jndiRealm.invalidHostnameVerifier=[{0}] not a valid class name for a HostnameVerifier
|
||||
jndiRealm.invalidSslProtocol=Given protocol [{0}] is invalid. It has to be one of [{1}]
|
||||
jndiRealm.invalidSslSocketFactory=[{0}] not a valid class name for an SSLSocketFactory
|
||||
jndiRealm.negotiatedTls=Negotiated tls connection using protocol [{0}]
|
||||
jndiRealm.open=Exception opening directory server connection
|
||||
jndiRealm.tlsClose=Exception closing tls response
|
||||
|
||||
lockOutRealm.authLockedUser=An attempt was made to authenticate the locked user [{0}]
|
||||
lockOutRealm.removeWarning=User [{0}] was removed from the failed users cache after [{1}] seconds to keep the cache size within the limit set
|
||||
|
||||
mdCredentialHandler.unknownEncoding=The encoding [{0}] is not supported so the current setting of [{1}] will still be used
|
||||
|
||||
memoryRealm.authenticateFailure=Username [{0}] NOT successfully authenticated
|
||||
memoryRealm.authenticateSuccess=Username [{0}] successfully authenticated
|
||||
memoryRealm.loadExist=Memory database file [{0}] cannot be read
|
||||
memoryRealm.loadPath=Loading users from memory database file [{0}]
|
||||
memoryRealm.readXml=Exception while reading memory database file
|
||||
memoryRealm.xmlFeatureEncoding=Exception configuring digester to permit java encoding names in XML files. Only IANA encoding names will be supported.
|
||||
|
||||
pbeCredentialHandler.invalidKeySpec=Unable to generate a password based key
|
||||
|
||||
realmBase.algorithm=Invalid message digest algorithm [{0}] specified
|
||||
realmBase.authenticateFailure=Username [{0}] NOT successfully authenticated
|
||||
realmBase.authenticateSuccess=Username [{0}] successfully authenticated
|
||||
realmBase.cannotGetRoles=Cannot get roles from principal [{0}]
|
||||
realmBase.createUsernameRetriever.ClassCastException=Class [{0}] is not an X509UsernameRetriever.
|
||||
realmBase.createUsernameRetriever.newInstance=Cannot create object of type [{0}].
|
||||
realmBase.credentialNotDelegated=Credential for user [{0}] has not been delegated though storing was requested
|
||||
realmBase.delegatedCredentialFail=Unable to obtain delegated credential for user [{0}]
|
||||
realmBase.digest=Error digesting user credentials
|
||||
realmBase.forbidden=Access to the requested resource has been denied
|
||||
realmBase.gotX509Username=Got user name from X509 certificate: [{0}]
|
||||
realmBase.gssContextNotEstablished=Authenticator implementation error: the passed security context is not fully established
|
||||
realmBase.gssNameFail=Failed to extract name from established GSSContext
|
||||
realmBase.hasRoleFailure=Username [{0}] does NOT have role [{1}]
|
||||
realmBase.hasRoleSuccess=Username [{0}] has role [{1}]
|
||||
|
||||
userDatabaseRealm.lookup=Exception looking up UserDatabase under key [{0}]
|
||||
userDatabaseRealm.noDatabase=No UserDatabase component found under key [{0}]
|
||||
51
java/org/apache/catalina/realm/LocalStrings_de.properties
Normal file
51
java/org/apache/catalina/realm/LocalStrings_de.properties
Normal file
@@ -0,0 +1,51 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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.
|
||||
|
||||
combinedRealm.authFail=Kann Benutzer [{0}] mit Realm [{1}] nicht authentisieren
|
||||
combinedRealm.authSuccess=Authentifizierter Benutzer [{0}] mit Realm [{1}]
|
||||
|
||||
dataSourceRealm.authenticateFailure=Benutzername [{0}] konnte NICHT authentifiziert werden
|
||||
dataSourceRealm.authenticateSuccess=Benutzername [{0}] konnte erfolgreich authentifiziert werden
|
||||
dataSourceRealm.getPassword.exception=Ausnahme beim Holen des Passwortes für [{0}]
|
||||
dataSourceRealm.getRoles.exception=Ausnahme beim Holen der Rollen für [{0}]
|
||||
|
||||
jaasRealm.accountExpired=Benutzername [{0}] konnte auf Grund eines abgelaufenen Kontos NICHT authentifiziert werden
|
||||
jaasRealm.authenticateFailure=Benutzername [{0}] konnte NICHT authentifiziert werden
|
||||
jaasRealm.credentialExpired=Benutzername [{0}] konnte auf Grund abgelaufener Zugangsdaten NICHT authentifiziert werden
|
||||
jaasRealm.failedLogin=Benutzername [{0}] konnte auf Grund einer fehlerhaften Anmeldung NICHT authentifiziert werden
|
||||
jaasRealm.loginContextCreated=JAAS LoginContext für Benutzername [{0}] erzeugt
|
||||
|
||||
jdbcRealm.authenticateFailure=Benutzername [{0}] konnte NICHT authentifiziert werden
|
||||
jdbcRealm.authenticateSuccess=Benutzername [{0}] konnte erfolgreich authentifiziert werden
|
||||
|
||||
jndiRealm.authenticateFailure=Benutzername [{0}] konnte NICHT authentifiziert werden
|
||||
jndiRealm.authenticateSuccess=Benutzername [{0}] konnte erfolgreich authentifiziert werden
|
||||
|
||||
lockOutRealm.authLockedUser=Es wurde versucht den gesperrten Benutzer [{0}] zu authentifizieren
|
||||
|
||||
memoryRealm.authenticateFailure=Benutzername [{0}] konnte NICHT authentifiziert werden
|
||||
memoryRealm.authenticateSuccess=Benutzername [{0}] konnte erfolgreich authentifiziert werden.\n
|
||||
memoryRealm.loadExist=Datei [{0}] für Memory Database kann nicht gelesen werden
|
||||
|
||||
realmBase.authenticateFailure=Benutzername [{0}] konnte NICHT authentifiziert werden
|
||||
realmBase.authenticateSuccess=Benutzername [{0}] konnte erfolgreich authentifiziert werden
|
||||
realmBase.createUsernameRetriever.ClassCastException=Klasse [{0}] ist keine X509UsernameRetriever Klasse.
|
||||
realmBase.digest=Fehler beim Anwenden des Digest auf die Benutzer-Credentials
|
||||
realmBase.forbidden=Zugriff auf die gewünschte Resource wurde verweigert.
|
||||
realmBase.gotX509Username=Benutzername aus dem X.509 Zertifikate extrahiert: [{0}]
|
||||
realmBase.hasRoleFailure=Benutzername [{0}] hat NICHT die Rolle [{1}]
|
||||
realmBase.hasRoleSuccess=Benutzername [{0}] hat die Rolle [{1}]
|
||||
|
||||
userDatabaseRealm.noDatabase=Keine UserDatabase Komponente unter dem Schlüssel [{0}] gefunden
|
||||
84
java/org/apache/catalina/realm/LocalStrings_es.properties
Normal file
84
java/org/apache/catalina/realm/LocalStrings_es.properties
Normal file
@@ -0,0 +1,84 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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.
|
||||
|
||||
combinedRealm.addRealm=Añadir reino [{0}], totalizando [{1}] reinos
|
||||
combinedRealm.authFail=No pude autenticar al usuario [{0}] con el reino [{1}]
|
||||
combinedRealm.authStart=Intentando autentica al usuario [{0}] con el reino [{1}]
|
||||
combinedRealm.authSuccess=Usuario autenticado [{0}] con reino [{1}]
|
||||
combinedRealm.getPassword=No se debería de llamar nunca al método getPassword()
|
||||
combinedRealm.getPrincipal=No se debería de llamar nunca al método getPrincipal()
|
||||
combinedRealm.realmStartFail=No pude arrancar reino [{0}]
|
||||
combinedRealm.unexpectedMethod=Una llamada inesperada se realizó a un método del reino combinado
|
||||
|
||||
dataSourceRealm.authenticateFailure=Nombre de usuario [{0}] NO autenticado con éxito
|
||||
dataSourceRealm.authenticateSuccess=Nombre de usuario [{0}] autenticado con éxito
|
||||
dataSourceRealm.close=Excepción cerrando conexión a base de datos
|
||||
dataSourceRealm.exception=Excepción realizando autenticación
|
||||
dataSourceRealm.getPassword.exception=Excepción recuperando contraseña para [{0}]
|
||||
dataSourceRealm.getRoles.exception=Excepción recuperando papeles para [{0}]
|
||||
|
||||
jaasCallback.username=Devuelto nombre de usuario [{0}]
|
||||
|
||||
jaasRealm.accountExpired=El usuario [{0}] NO ha sido autentificado porque ha expirado su cuenta
|
||||
jaasRealm.authenticateFailure=Nombre de usuario [{0}] NO autenticado con éxito
|
||||
jaasRealm.authenticateSuccess=Nombre de usuario [{0}] autenticado con éxito como Principal [{1}] -- También se ha creado el Asunto
|
||||
jaasRealm.beginLogin=JAASRealm login requerido para nombre de usuario [{0}] usando LoginContext para aplicación [{1}]
|
||||
jaasRealm.checkPrincipal=Revisando Principal [{0}] [{1}]
|
||||
jaasRealm.credentialExpired=El usuario [{0}] NO ha sido autentificado porque ha expirado su credencial
|
||||
jaasRealm.failedLogin=El usuario [{0}] NO ha sido autentificado porque ha fallado el login
|
||||
jaasRealm.loginContextCreated=JAAS LoginContext creado para nombre de usuario [{0}]
|
||||
jaasRealm.loginException=Excepción de Login autenticando nombre de usuario [{0}]
|
||||
jaasRealm.rolePrincipalAdd=Añadiend papel Principal [{0}] a los papeles de este usuario Principal
|
||||
jaasRealm.rolePrincipalFailure=No se han hallado papeles de Principal válidos.
|
||||
jaasRealm.unexpectedError=Error inesperado
|
||||
jaasRealm.userPrincipalFailure=No se ha hallado usuario Principal
|
||||
jaasRealm.userPrincipalSuccess=El Principal [{0}] es una clase válida de usuario. La vamos a usar como usuario Principal.
|
||||
|
||||
jdbcRealm.authenticateFailure=El usuario [{0}] NO ha sido autentificado correctamente
|
||||
jdbcRealm.authenticateSuccess=El usuario [{0}] ha sido autentificado correctamente
|
||||
jdbcRealm.close=Excepción al cerrar la conexión a la base de datos
|
||||
jdbcRealm.exception=Excepción al realizar la autentificación
|
||||
jdbcRealm.open=Excepción abriendo la conexión a la base de datos
|
||||
jdbcRealm.open.invalidurl=El conductor [{0}] no soporta la url [{1}]
|
||||
|
||||
jndiRealm.authenticateFailure=Autentificación fallida para el usuario [{0}]
|
||||
jndiRealm.authenticateSuccess=Autentificación correcta para el usuario [{0}]
|
||||
jndiRealm.close=Excepción al cerrar la conexión al servidor de directorio
|
||||
jndiRealm.exception=Excepción al realizar la autentificación
|
||||
jndiRealm.open=Excepción al abrir la conexión al servidor de directorio
|
||||
|
||||
lockOutRealm.authLockedUser=Se ha intentado autenticar al usuario bloqueado [{0}]
|
||||
lockOutRealm.removeWarning=Se ha quitado al usuario [{0}] de la caché de usuarios fallidos tras [{1}] secgundos para mantener la medida de caché dentro de los límites
|
||||
|
||||
memoryRealm.authenticateFailure=Autentificación fallida para el usuario [{0}]
|
||||
memoryRealm.authenticateSuccess=Autentificación correcta para el usuario [{0}]
|
||||
memoryRealm.loadExist=El fichero de usuarios [{0}] no ha podido ser leído
|
||||
memoryRealm.loadPath=Cargando los usuarios desde el fichero [{0}]
|
||||
memoryRealm.readXml=Excepción mientras se leía el fichero de usuarios
|
||||
memoryRealm.xmlFeatureEncoding=Excepción al configurar resumidor para permitir nombres con codificación java en ficheros XML. Sóllo se soportan nombres con codificación IANA.
|
||||
|
||||
realmBase.algorithm=El algoritmo resumen (digest) [{0}] es inválido
|
||||
realmBase.authenticateFailure=Nombre de usuario [{0}] NO autenticado con éxito
|
||||
realmBase.authenticateSuccess=Nombre de usuario [{0}] autenticado con éxito
|
||||
realmBase.createUsernameRetriever.ClassCastException=La clase [{0}] no es una X509UsernameRetriever.
|
||||
realmBase.delegatedCredentialFail=No pude obtener credenciales de delegado para el usuario [{0}]
|
||||
realmBase.digest=Error procesando las credenciales del usuario
|
||||
realmBase.forbidden=El acceso al recurso pedido ha sido denegado
|
||||
realmBase.gssNameFail=No pude extraer el nombre desde el GSSContext establecido
|
||||
realmBase.hasRoleFailure=El usuario [{0}] NO desempeña el papel de [{1}]
|
||||
realmBase.hasRoleSuccess=El usuario [{0}] desempeña el papel de [{1}]
|
||||
|
||||
userDatabaseRealm.lookup=Excepción buscando en Base de datos de Usuario mediante la clave [{0}]
|
||||
userDatabaseRealm.noDatabase=No se ha hallado componente de Base de datos de Usuario mediante la clave [{0}]
|
||||
103
java/org/apache/catalina/realm/LocalStrings_fr.properties
Normal file
103
java/org/apache/catalina/realm/LocalStrings_fr.properties
Normal file
@@ -0,0 +1,103 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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.
|
||||
|
||||
combinedRealm.addRealm=Ajout du royaume [{0}], [{1}] royaumes au total
|
||||
combinedRealm.authFail=Echec d''authentification de l''utilisateur [{0}] avec le domaine [{1}]
|
||||
combinedRealm.authStart=Tentative d''authentifier l''utilisateur [{0}] avec le royaume [{1}]
|
||||
combinedRealm.authSuccess=Authentifié l''utilisateur [{0}] avec le domaine [{1}]
|
||||
combinedRealm.getPassword=La méthode getPassword() ne doit jamais être appelée
|
||||
combinedRealm.getPrincipal=La méthode getPrincipal() ne devrait jamais être appelée
|
||||
combinedRealm.realmStartFail=Impossible de démarrer le royaume [{0}]
|
||||
combinedRealm.unexpectedMethod=Un appel de méthode inattendu à été effectué sur le royaumes combiné
|
||||
|
||||
credentialHandler.invalidStoredCredential=Le royaume a fourni des identifiants [{0}] invalides à comparer avec ceux fournis par le client
|
||||
|
||||
dataSourceRealm.authenticateFailure=Le nom d''utilisateur [{0}] n''a pas été authentifié
|
||||
dataSourceRealm.authenticateSuccess=Le nom d''utilisateur [{0}] a été authentifié avec succès
|
||||
dataSourceRealm.close=Exception lors de la fermeture de la connection vers la base de données
|
||||
dataSourceRealm.exception=Exception lors de l'anthentification
|
||||
dataSourceRealm.getPassword.exception=Exception lors de la récupération du mot de passe pour [{0}]
|
||||
dataSourceRealm.getRoles.exception=Exception lors de la récupération des rôles de [{0}]
|
||||
|
||||
jaasCallback.username=Nom d''utilisateur renvoyé [{0}]
|
||||
|
||||
jaasRealm.accountExpired=le nom d''utilisateur [{0}] N''A PAS été authentifié car le compte a expiré
|
||||
jaasRealm.authenticateFailure=Le nom d''utilisateur [{0}] n''a pas été authentifié avec succès
|
||||
jaasRealm.authenticateSuccess=le nom d''utilisateur [{0}] a été authentifié avec succès
|
||||
jaasRealm.beginLogin=La connection avec le JAASRealm a demandé le nom d''utilisateur [{0}] en utilisant le LoginContext de l''application [{1}]
|
||||
jaasRealm.checkPrincipal=Vérification du principal [{0}] [{1}]
|
||||
jaasRealm.credentialExpired=le nom d''utilisateur [{0}] N''A PAS été authentifié car son crédit a expiré (expired credential)
|
||||
jaasRealm.failedLogin=le nom d''utilisateur [{0}] N''A PAS été authentifié car son contrôle d''accès (login) a échoué
|
||||
jaasRealm.loginContextCreated=Le LoginContext JAAS a été crée pour le nom d''utilisateur [{0}]
|
||||
jaasRealm.loginException=Exception lors de l''authentification par login du nom d''utilisateur [{0}]
|
||||
jaasRealm.rolePrincipalAdd=Ajout du rôle Pincipal [{0}] aux rôles du principal de l''utilisateur
|
||||
jaasRealm.rolePrincipalFailure=Aucun principal avec un rôle valide trouvé
|
||||
jaasRealm.unexpectedError=Erreur inattendue
|
||||
jaasRealm.userPrincipalFailure=Aucun principal valide trouvé
|
||||
jaasRealm.userPrincipalSuccess=Le principal [{0}] est une classe utilisateur valide, elle sera utilisée comme principal de l''utilisateur
|
||||
|
||||
jdbcRealm.authenticateFailure=le nom d''utilisateur [{0}] N''A PAS été authentifié
|
||||
jdbcRealm.authenticateSuccess=le nom d''utilisateur [{0}] a été authentifié avec succès
|
||||
jdbcRealm.close=Exception lors de la fermeture de la connexion à la base de données
|
||||
jdbcRealm.exception=Exception pendant le traitement de l'authentification
|
||||
jdbcRealm.open=Exception lors de l'ouverture de la base de données
|
||||
jdbcRealm.open.invalidurl=Le pilote [{0}] ne supporte pas l''URL [{1}]
|
||||
|
||||
jndiRealm.authenticateFailure=Le nom d''utilisateur [{0}] N''A PAS été authentifié
|
||||
jndiRealm.authenticateSuccess=Le nom d''utilisateur [{0}] a été authentifié avec succès
|
||||
jndiRealm.cipherSuites=La suite de chiffres [{0}] a été activée pour la connection TLS
|
||||
jndiRealm.close=Exception lors de la fermeture de la connexion au serveur d'accès (directory server)
|
||||
jndiRealm.emptyCipherSuites=Une chaîne vide est donnée comme suite de chiffres, la suite de chiffres par défaut sera utilisée
|
||||
jndiRealm.exception=Exception pendant le traitement de l'authentification
|
||||
jndiRealm.exception.retry=Erreur pendant l'authentification, nouvel essai
|
||||
jndiRealm.invalidHostnameVerifier=[{0}] n''est pas un nom de classe valide pour un HostnameVerifier
|
||||
jndiRealm.invalidSslProtocol=Le protocole fourni [{0}] est invalide, il doit être parmi [{1}]
|
||||
jndiRealm.invalidSslSocketFactory=[{0}] n''est pas un nom de classe valide pour une SSLSocketFactory
|
||||
jndiRealm.negotiatedTls=La connection TLS a été négociée en utilisant le protocole [{0}]
|
||||
jndiRealm.open=Exception lors de l'ouverture de la connexion au serveur d'accès (directory server)
|
||||
jndiRealm.tlsClose=Exception en fermant la réponse TLS
|
||||
|
||||
lockOutRealm.authLockedUser=Une tentative d''authentification a été effectuée pour l''utilisateur verrouillé ("locked user") [{0}]
|
||||
lockOutRealm.removeWarning=L''utilisateur [{0}] a été enlevé du cache des utilisateurs en échec après [{1}] secondes pour garder la taille du cache dans les limites définies
|
||||
|
||||
mdCredentialHandler.unknownEncoding=L''encodage [{0}] n''est pas supporté donc la configuration actuelle [{1}] va continuer à être utilisée
|
||||
|
||||
memoryRealm.authenticateFailure=le nom d''utilisateur [{0}] N''A PAS été authentifié
|
||||
memoryRealm.authenticateSuccess=le nom d''utilisateur [{0}] a été authentifié avec succès
|
||||
memoryRealm.loadExist=Le fichier base de données mémoire (memory database) [{0}] ne peut être lu
|
||||
memoryRealm.loadPath=Chargement des utilisateurs depuis le fichier base de données mémoire (memory database) [{0}]
|
||||
memoryRealm.readXml=Exception lors de la lecture du fichier base de données mémoire (memory database)
|
||||
memoryRealm.xmlFeatureEncoding=Exception lors de la configuration du Digester pour permettre des noms d'encodage Java dans les fichiers XML, seuls le noms IANA seront supportés
|
||||
|
||||
pbeCredentialHandler.invalidKeySpec=Impossible de générer une clé basée sur le mot de passe
|
||||
|
||||
realmBase.algorithm=L''algorithme de hachage de message [{0}] indiqué est invalide
|
||||
realmBase.authenticateFailure=Le nom d''utilisateur [{0}] N''A PAS été authentifié
|
||||
realmBase.authenticateSuccess=Le nom d''utilisateur [{0}] a été authentifié avec succès
|
||||
realmBase.cannotGetRoles=Impossible d''obtenir les rôles du principal [{0}]
|
||||
realmBase.createUsernameRetriever.ClassCastException=La classe [{0}] n''est pas un X509UsernameRetriever.
|
||||
realmBase.createUsernameRetriever.newInstance=Impossible de créer un objet du type [{0}]
|
||||
realmBase.credentialNotDelegated=Les identifiants de l'utilisateur [{0}} n'ont pas été délégués alors que leur stockage a été requis
|
||||
realmBase.delegatedCredentialFail=Impossible d''obtenir les identifiants délégués pour l''utilisateur [{0}]
|
||||
realmBase.digest=Erreur lors du hachage de l''identifiant utilisateur
|
||||
realmBase.forbidden=L'accès à la ressource demandée a été interdit
|
||||
realmBase.gotX509Username=Obtenu le nom d''utilisateur dans le certificat X509: [{0}]
|
||||
realmBase.gssContextNotEstablished=Erreur d'implémentation de l'authenticateur: le contexte de sécurité passé n'est pas complètement établi
|
||||
realmBase.gssNameFail=Impossible d'extraire le nom du GSSContext qui a été établi
|
||||
realmBase.hasRoleFailure=Le nom d''utilisateur [{0}] N''A PAS de rôle [{1}]
|
||||
realmBase.hasRoleSuccess=Le nom d''utilisateur [{0}] a pour rôle [{1}]
|
||||
|
||||
userDatabaseRealm.lookup=Exception lors de la recherche dans la base de données utilisateurs avec la clé [{0}]
|
||||
userDatabaseRealm.noDatabase=Aucun composant base de données utilisateurs trouvé pour la clé [{0}]
|
||||
102
java/org/apache/catalina/realm/LocalStrings_ja.properties
Normal file
102
java/org/apache/catalina/realm/LocalStrings_ja.properties
Normal file
@@ -0,0 +1,102 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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.
|
||||
|
||||
combinedRealm.addRealm=Realm[{0}]を追加し、合計[{1}]Realmを作成します。
|
||||
combinedRealm.authFail=レルム [{1}] でユーザー [{0}] の認証に失敗しました。
|
||||
combinedRealm.authStart=ユーザー [{0}] をRealm [{1}] で認証します。
|
||||
combinedRealm.authSuccess=レルム [{1}] でユーザー [{0}] を認証しました。
|
||||
combinedRealm.getPassword=getPassword() メソッドを呼び出してはいけません。
|
||||
combinedRealm.getPrincipal=getPrincipal()メソッドは決して呼び出されるべきではありません。
|
||||
combinedRealm.realmStartFail=Realm[{0}]の開始に失敗しました。
|
||||
combinedRealm.unexpectedMethod=Combined Realmについて予期せぬメソッド呼び出しが発生しました。
|
||||
|
||||
credentialHandler.invalidStoredCredential=ユーザ提供の資格情報とマッチするためにRealm によって提供された無効な格納された資格情報文字列[[{0}]
|
||||
|
||||
dataSourceRealm.authenticateFailure=ユーザ名 [{0}] は認証に失敗しました
|
||||
dataSourceRealm.authenticateSuccess=ユーザ名 [{0}] は認証に成功しました
|
||||
dataSourceRealm.close=データベース接続をクローズ中の例外です
|
||||
dataSourceRealm.exception=認証を実行中の例外です
|
||||
dataSourceRealm.getPassword.exception=[{0}] のパスワードを取得中に異常が発生しました。
|
||||
dataSourceRealm.getRoles.exception=[{0}] のロールを取得する途中で例外が発生しました。
|
||||
|
||||
jaasCallback.username=返されたユーザー名[{0}]
|
||||
|
||||
jaasRealm.accountExpired=ユーザ名 [{0}] はアカウントの期限が切れているために認証されません
|
||||
jaasRealm.authenticateFailure=ユーザー名[{0}]は正常に認証されませんでした
|
||||
jaasRealm.authenticateSuccess=ユーザ名 [{0}] は認証に成功しました
|
||||
jaasRealm.beginLogin=アプリケーション[{1}]のLoginContextを使用して、ユーザー名[{0}]に対するJAASRealmログインが要求されました。
|
||||
jaasRealm.checkPrincipal=プリンシパル[{0}] [{1}]をチェックします。
|
||||
jaasRealm.credentialExpired=ユーザ名 [{0}] は証明書の期限が切れたために認証されません
|
||||
jaasRealm.failedLogin=ユーザ名 [{0}] はログインに失敗したために認証されませんでした
|
||||
jaasRealm.loginContextCreated=ユーザー名[{0}]用に作成されたJAAS LoginContext
|
||||
jaasRealm.loginException=ユーザ名 [{0}] の認証中にログイン例外が発生しました
|
||||
jaasRealm.rolePrincipalAdd=このユーザープリンシパルロールにロールプリンシパル[{0}]を追加
|
||||
jaasRealm.rolePrincipalFailure=有効な役割はありません。
|
||||
jaasRealm.unexpectedError=予測しないエラーです
|
||||
jaasRealm.userPrincipalFailure=有効なユーザープリンシパルが見つかりません。
|
||||
jaasRealm.userPrincipalSuccess=プリンシパル[{0}]は有効なユーザークラスです。 これをユーザープリンシパルとして使用します。
|
||||
|
||||
jdbcRealm.authenticateFailure=ユーザ名 [{0}] は認証に失敗しました
|
||||
jdbcRealm.authenticateSuccess=ユーザ名 [{0}] は認証に成功しました
|
||||
jdbcRealm.close=データベース接続クローズ中の例外です
|
||||
jdbcRealm.exception=認証実行中の例外です
|
||||
jdbcRealm.open=データベース接続オープン中に例外が発生しました
|
||||
jdbcRealm.open.invalidurl=ドライバー [{0}] は url [{1}] に対応していません。
|
||||
|
||||
jndiRealm.authenticateFailure=ユーザ名 [{0}] は認証に失敗しました
|
||||
jndiRealm.authenticateSuccess=ユーザ名 [{0}] は認証に成功しました
|
||||
jndiRealm.cipherSuites=TLS 接続で暗号スイート [{0}] を有効化しました。
|
||||
jndiRealm.close=ディレクトリサーバ接続クローズ中の例外です
|
||||
jndiRealm.emptyCipherSuites=指定された暗号スイートの空の文字列。 デフォルトの暗号スイートを使用します。
|
||||
jndiRealm.exception=認証実行中の例外です
|
||||
jndiRealm.exception.retry=認証中に例外が発生しました。再試行します。
|
||||
jndiRealm.invalidHostnameVerifier=[{0}]はHostnameVerifierの有効なクラス名ではありません。
|
||||
jndiRealm.invalidSslProtocol=指定されたプロトコル[{0}]は無効です。 [{1}]のいずれかでなければなりません。
|
||||
jndiRealm.invalidSslSocketFactory=[{0}]はSSLSocketFactoryの有効なクラス名ではありません
|
||||
jndiRealm.negotiatedTls=プロトコル[{0}]を使用して交渉されたTLS接続
|
||||
jndiRealm.open=ディレクトリサーバ接続オープン中の例外です
|
||||
jndiRealm.tlsClose=TLSレスポンスを閉じる際の例外
|
||||
|
||||
lockOutRealm.authLockedUser=ロックされたユーザー [{0}] の認証が試行されました。
|
||||
lockOutRealm.removeWarning=キャッシュサイズが制限内に収まるようにするため、[{1}]秒後にユーザー[{0}]が失敗したユーザーキャッシュから削除されました。
|
||||
|
||||
mdCredentialHandler.unknownEncoding=エンコーディング [{0}] には未対応のため現在の設定 [{1}] を使用します。
|
||||
|
||||
memoryRealm.authenticateFailure=ユーザ名 [{0}] は認証に失敗しました
|
||||
memoryRealm.authenticateSuccess=ユーザ名 [{0}] は認証に成功しました
|
||||
memoryRealm.loadExist=メモリデータベースファイル [{0}] を読むことができません
|
||||
memoryRealm.loadPath=メモリデータベースファイル [{0}] からユーザをロードします
|
||||
memoryRealm.readXml=メモリデータベースファイルを読み込み中の例外です
|
||||
memoryRealm.xmlFeatureEncoding=XMLファイルのJavaエンコーディング名を許可するためにdigesterを設定する例外。 IANAのエンコーディング名のみがサポートされます。
|
||||
|
||||
pbeCredentialHandler.invalidKeySpec=パスワードベースの鍵を生成できません。
|
||||
|
||||
realmBase.algorithm=無効なメッセージダイジェストアルゴリズム [{0}] が指定されています
|
||||
realmBase.authenticateFailure=ユーザ名 [{0}] は認証に失敗しました
|
||||
realmBase.authenticateSuccess=ユーザ名 [{0}] は認証に成功しました
|
||||
realmBase.cannotGetRoles=プリンシパル[{0}]からロールを取得できません
|
||||
realmBase.createUsernameRetriever.ClassCastException=クラス[{0}]はX509UsernameRetrieverではありません。
|
||||
realmBase.createUsernameRetriever.newInstance=タイプ[{0}]のオブジェクトを作成できません。
|
||||
realmBase.delegatedCredentialFail=ユーザー[{0}]の委任された資格情報を取得できません
|
||||
realmBase.digest=ユーザの証明書のダイジェストエラー
|
||||
realmBase.forbidden=要求されたリソースへのアクセスが拒否されました
|
||||
realmBase.gotX509Username=X509証明書のユーザー名を取得しました:[{0}]
|
||||
realmBase.gssContextNotEstablished=Authenticator 実装エラー:渡されたセキュリティコンテキストが完全に確立されていません。
|
||||
realmBase.gssNameFail=確立されたGSSContextから名前を抽出できませんでした。
|
||||
realmBase.hasRoleFailure=ユーザ名 [{0}] はロール [{1}] を持っていません
|
||||
realmBase.hasRoleSuccess=ユーザ名 [{0}] はロール [{1}] を持っています
|
||||
|
||||
userDatabaseRealm.lookup=キー [{0}] でユーザデータベースを検索中の例外です
|
||||
userDatabaseRealm.noDatabase=キー [{0}] でユーザデータベースコンポーネントが見つかりません
|
||||
103
java/org/apache/catalina/realm/LocalStrings_ko.properties
Normal file
103
java/org/apache/catalina/realm/LocalStrings_ko.properties
Normal file
@@ -0,0 +1,103 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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.
|
||||
|
||||
combinedRealm.addRealm=Realm [{0}]을(를) 추가하여, 전체 Realm 개수는 [{1}]이(가) 됩니다.
|
||||
combinedRealm.authFail=사용자 [{0}]을(를) realm [{1}]을(를) 사용하여 인증하지 못했습니다.
|
||||
combinedRealm.authStart=사용자 [{0}]을(를), realm [{1}]을(를) 사용하여 인증 시도 중
|
||||
combinedRealm.authSuccess=사용자 [{0}]을(를) realm [{1}]을(를) 사용하여 인증했습니다.
|
||||
combinedRealm.getPassword=getPassword() 메소드는 절대 호출되서는 안됩니다.
|
||||
combinedRealm.getPrincipal=getPrincipal() 메소드는 절대로 호출되서는 안됩니다.
|
||||
combinedRealm.realmStartFail=[{0}] realm을 시작하지 못했습니다.
|
||||
combinedRealm.unexpectedMethod=CombinedRealm의 메소드에 예기치 않은 호출이었습니다.
|
||||
|
||||
credentialHandler.invalidStoredCredential=사용자가 제공한 credentials과 부합하는지 검사하기 위하여, 유효하지 않은 저장된 credentials 문자열 [{0}]이(가), Realm에 의해 제공되었습니다.
|
||||
|
||||
dataSourceRealm.authenticateFailure=사용자명 [{0}]은(는) 성공적으로 인증되지 않았습니다.
|
||||
dataSourceRealm.authenticateSuccess=사용자명 [{0}]이(가) 성공적으로 인증되었습니다.
|
||||
dataSourceRealm.close=데이터베이스 연결을 닫는 중 예외 발생
|
||||
dataSourceRealm.exception=인증 처리 수행 중 예외 발생
|
||||
dataSourceRealm.getPassword.exception=[{0}]을(를) 위한 비밀번호를 조회하던 중 예외 발생
|
||||
dataSourceRealm.getRoles.exception=사용자 [{0}]을(를) 위한 역할들을 조회하는 중 예외 발생
|
||||
|
||||
jaasCallback.username=반환된 사용자명 [{0}]
|
||||
|
||||
jaasRealm.accountExpired=사용자명 [{0}]은(는) 만료된 계정이라서 인증되지 않았습니다.
|
||||
jaasRealm.authenticateFailure=사용자명 [{0}]은(는) 성공적으로 인증되지 못했습니다.
|
||||
jaasRealm.authenticateSuccess=사용자명 [{0}]이(가) 성공적으로 Principal [{1}](으)로서 인증되었습니다 -- Subject 또한 생성되었습니다.
|
||||
jaasRealm.beginLogin=애플리케이션 [{1}]을(를) 위한 LoginContext를 사용하여, 사용자명 [{0}]을(를) 위한 JAASRealm 로그인이 요청되었습니다.
|
||||
jaasRealm.checkPrincipal=Principal [{0}] [{1}]을(를) 점검합니다.
|
||||
jaasRealm.credentialExpired=만료된 credentials로 인하여, 사용자명 [{0}]이(가) 인증되지 않았습니다.
|
||||
jaasRealm.failedLogin=사용자명 [{0}]은(는) 로그인 실패로 인하여 인증되지 않았습니다.
|
||||
jaasRealm.loginContextCreated=사용자명 [{0}]을(를) 위해 생성된 JAAS LoginContext
|
||||
jaasRealm.loginException=사용자 이름 [{0}]을(를) 인증하는 중 로그인 예외 발생
|
||||
jaasRealm.rolePrincipalAdd=이 사용자 Principal의 역할들에, 역할 Principal [{0}]을(를) 추가합니다.
|
||||
jaasRealm.rolePrincipalFailure=유효한 역할 Principal들을 찾을 수 없습니다.
|
||||
jaasRealm.unexpectedError=예기치 않은 오류
|
||||
jaasRealm.userPrincipalFailure=유효한 사용자 Principal을 찾을 수 없습니다.
|
||||
jaasRealm.userPrincipalSuccess=Principal [{0}]은(는) 유효한 사용자 클래스입니다. 이를 사용자 Principal로 사용하겠습니다.
|
||||
|
||||
jdbcRealm.authenticateFailure=사용자명 [{0}]이(가) 성공적으로 인증되지 못했습니다.
|
||||
jdbcRealm.authenticateSuccess=사용자명 [{0}]이(가) 성공적으로 인증되었습니다.
|
||||
jdbcRealm.close=데이터베이스 연결을 닫는 중 예외 발생
|
||||
jdbcRealm.exception=인증 처리 수행 중 예외 발생
|
||||
jdbcRealm.open=데이터베이스 연결을 여는 중 예외 발생
|
||||
jdbcRealm.open.invalidurl=드라이버 [{0}]은(는) URL [{1}]을(를) 지원하지 않습니다.
|
||||
|
||||
jndiRealm.authenticateFailure=사용자명 [{0}]이(가) 성공적으로 인증되지 못했습니다.
|
||||
jndiRealm.authenticateSuccess=사용자명 [{0}]이(가) 성공적으로 인증되었습니다.
|
||||
jndiRealm.cipherSuites=이 tls 연결을 위한 cipher suite들로서, [{0}]을(를) 사용 가능하게 합니다.
|
||||
jndiRealm.close=디렉토리 서버 연결을 닫는 중 예외 발생
|
||||
jndiRealm.emptyCipherSuites=주어진 cipher suite들에 빈 문자열이 설정되었습니다. 기본 cipher suite들을 사용합니다.
|
||||
jndiRealm.exception=인증 처리 수행 중 예외 발생
|
||||
jndiRealm.exception.retry=인증 처리 수행 중 예외 발생. 재시도합니다...
|
||||
jndiRealm.invalidHostnameVerifier=[{0}]은(는), HostnameVerifier를 위한 클래스 이름으로서, 유효하지 않습니다.
|
||||
jndiRealm.invalidSslProtocol=주어진 프로토콜 [{0}]은(는) 유효하지 않습니다. 반드시 [{1}] 중의 하나여야 합니다.
|
||||
jndiRealm.invalidSslSocketFactory=[{0}]은(는) SSLSocketFactory 객체를 위해 유효한 클래스 이름이 아닙니다.
|
||||
jndiRealm.negotiatedTls=프로토콜 [{0}]을(를) 사용하여 TLS 연결을 negotiate 했습니다.
|
||||
jndiRealm.open=디렉토리 서버 연결을 여는 중 예외 발생
|
||||
jndiRealm.tlsClose=tls 응답을 닫는 중 예외 발생
|
||||
|
||||
lockOutRealm.authLockedUser=잠금 상태인 사용자 [{0}]을(를) 인증하려는 시도가 이루어졌습니다.
|
||||
lockOutRealm.removeWarning=캐시 크기를 한계값 내에서 유지하기 위하여, 사용자 [{0}]을(를), [{1}]초 후에 실패 사용자 캐시로부터 제거했습니다.
|
||||
|
||||
mdCredentialHandler.unknownEncoding=인코딩 [{0}]이(가) 지원되지 않아서, 현 설정 [{1}]이(가) 계속 사용될 것입니다.
|
||||
|
||||
memoryRealm.authenticateFailure=사용자명 [{0}]이(가) 성공적으로 인증되지 못했습니다.
|
||||
memoryRealm.authenticateSuccess=사용자명 [{0}]이(가) 성공적으로 인증되었습니다.
|
||||
memoryRealm.loadExist=메모리 데이터베이스 파일 [{0}]을(를) 읽을 수 없습니다.
|
||||
memoryRealm.loadPath=메모리 데이터베이스 파일 [{0}](으)로부터 사용자들을 로드합니다.
|
||||
memoryRealm.readXml=메모리 데이터베이스 파일을 읽는 중 예외 발생
|
||||
memoryRealm.xmlFeatureEncoding=XML 파일들에서 자바 인코딩 이름들을 허용하기 위해 digester를 설정하는 중 예외 발생. 오직 IANA 인코딩 이름들만 지원될 것입니다.
|
||||
|
||||
pbeCredentialHandler.invalidKeySpec=비밀번호 기반의 키를 생성할 수 없습니다.
|
||||
|
||||
realmBase.algorithm=유효하지 않은 메시지 Digest 알고리즘 [{0}]이(가) 지정되었습니다.
|
||||
realmBase.authenticateFailure=사용자명 [{0}]이(가) 성공적으로 인증되지 못했습니다.
|
||||
realmBase.authenticateSuccess=사용자명 [{0}]이(가) 성공적으로 인증되었습니다.
|
||||
realmBase.cannotGetRoles=Principal [{0}](으)로부터 역할들을 얻을 수 없습니다.
|
||||
realmBase.createUsernameRetriever.ClassCastException=클래스 [{0}]이(가) X509UsernameRetriever 타입이 아닙니다.
|
||||
realmBase.createUsernameRetriever.newInstance=타입이 [{0}]인 객체를 생성할 수 없습니다.
|
||||
realmBase.credentialNotDelegated=인증서 저장 옵션이 요청되었지만, 사용자 [{0}]을(를) 위한 인증서 대리 처리가 사용 가능하지 않습니다.
|
||||
realmBase.delegatedCredentialFail=사용자 [{0}]을(를) 위한 대리 인증서를 얻을 수 없습니다.
|
||||
realmBase.digest=사용자의 credentials를 digest하는 중 오류 발생
|
||||
realmBase.forbidden=요청된 리소스에 대한 접근이 거부되었습니다.
|
||||
realmBase.gotX509Username=X509 인증서로부터 사용자 이름을 구했습니다: [{0}]
|
||||
realmBase.gssContextNotEstablished=Authenticator 구현 오류: 전달된 보안 컨텍스트가 완전히 확립되지 않았습니다.
|
||||
realmBase.gssNameFail=확립된 GSSContext로부터, 이름을 추출하지 못했습니다.
|
||||
realmBase.hasRoleFailure=사용자명 [{0}]은(는) 역할 [{1}]을(를) 가지고 있지 않습니다.
|
||||
realmBase.hasRoleSuccess=사용자명 [{0}]이(가) 역할 [{1}]을(를) 가지고 있습니다.
|
||||
|
||||
userDatabaseRealm.lookup=키 [{0}]을(를) 사용하여 사용자 데이터베이스를 찾는 중 예외 발생
|
||||
userDatabaseRealm.noDatabase=키 [{0}]을(를) 사용하여 UserDatabase 구성요소를 찾을 수 없습니다.
|
||||
18
java/org/apache/catalina/realm/LocalStrings_ru.properties
Normal file
18
java/org/apache/catalina/realm/LocalStrings_ru.properties
Normal file
@@ -0,0 +1,18 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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.
|
||||
|
||||
lockOutRealm.authLockedUser=Заблокированный пользователь [{0}] совершил попытку авторизоваться
|
||||
|
||||
realmBase.forbidden=Доступ к запрашиваемому ресурсу был заблокирован
|
||||
56
java/org/apache/catalina/realm/LocalStrings_zh_CN.properties
Normal file
56
java/org/apache/catalina/realm/LocalStrings_zh_CN.properties
Normal file
@@ -0,0 +1,56 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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.
|
||||
|
||||
combinedRealm.authFail=无法使用域[{1}]对用户[{0}]进行身份验证
|
||||
combinedRealm.authSuccess=认证用户[{0}],权限[{1}]
|
||||
|
||||
dataSourceRealm.getPassword.exception=获取用户名[{0}]对应的密码失败。
|
||||
dataSourceRealm.getRoles.exception=:)检索角色[{0}]异常
|
||||
|
||||
jaasCallback.username=返回用户名 [{0}]
|
||||
|
||||
jaasRealm.authenticateFailure=用户 [{0}] 认证失败
|
||||
jaasRealm.authenticateSuccess=用户名 [{0}] 已被成功认证为身份 [{1}] -- 主体也已创建
|
||||
jaasRealm.failedLogin=由于登录失败,用户名 [{0}] 无法授权
|
||||
jaasRealm.loginContextCreated=为用户名创建的JAAS 登陆上下文[{0}]
|
||||
jaasRealm.loginException=登录异常,认证用户名 [{0}]
|
||||
|
||||
jdbcRealm.authenticateFailure=用户名称[{0}]未校验成功
|
||||
jdbcRealm.open=打开数据库连接时发生异常
|
||||
|
||||
jndiRealm.authenticateFailure=用户名[{0}]没有成功认证
|
||||
jndiRealm.authenticateSuccess=用户名[{0}]成功认证
|
||||
jndiRealm.cipherSuites=启用 [{0}] 作为 TLS 连接的加密套件。
|
||||
jndiRealm.exception=执行认证异常
|
||||
jndiRealm.negotiatedTls=使用协议[{0}]协商的TLS连接
|
||||
jndiRealm.open=打开目录服务器链接异常
|
||||
|
||||
lockOutRealm.authLockedUser=尝试对锁定的用户[{0}]进行身份验证
|
||||
|
||||
memoryRealm.loadExist=内存数据库文件[{0}]无法读取
|
||||
memoryRealm.loadPath=从内存数据库文件 [{0}] 加载用户
|
||||
memoryRealm.readXml=读取内存数据库文件时出现异常
|
||||
memoryRealm.xmlFeatureEncoding=配置Digester以允许XML文件中的java编码名称的异常。只支持IANA编码名称。
|
||||
|
||||
pbeCredentialHandler.invalidKeySpec=无法生成基于密码的密钥
|
||||
|
||||
realmBase.authenticateFailure=用户名 [{0}] 认证失败
|
||||
realmBase.createUsernameRetriever.ClassCastException=类[{0}] 不是一个X509UsernameRetriever.
|
||||
realmBase.digest=对用户凭证摘要发生错误
|
||||
realmBase.forbidden=已拒绝访问所请求的资源
|
||||
realmBase.hasRoleFailure=用户[{0}]没有角色[{1}]
|
||||
realmBase.hasRoleSuccess=用户名[{0}] 有角色[{1}]
|
||||
|
||||
userDatabaseRealm.noDatabase=未找到key[{0}]对应的UserDatabase组件。
|
||||
428
java/org/apache/catalina/realm/LockOutRealm.java
Normal file
428
java/org/apache/catalina/realm/LockOutRealm.java
Normal file
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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 org.apache.catalina.realm;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.ietf.jgss.GSSContext;
|
||||
import org.ietf.jgss.GSSCredential;
|
||||
import org.ietf.jgss.GSSException;
|
||||
import org.ietf.jgss.GSSName;
|
||||
|
||||
/**
|
||||
* This class extends the CombinedRealm (hence it can wrap other Realms) to
|
||||
* provide a user lock out mechanism if there are too many failed
|
||||
* authentication attempts in a given period of time. To ensure correct
|
||||
* operation, there is a reasonable degree of synchronisation in this Realm.
|
||||
* This Realm does not require modification to the underlying Realms or the
|
||||
* associated user storage mechanisms. It achieves this by recording all failed
|
||||
* logins, including those for users that do not exist. To prevent a DOS by
|
||||
* deliberating making requests with invalid users (and hence causing this cache
|
||||
* to grow) the size of the list of users that have failed authentication is
|
||||
* limited.
|
||||
*/
|
||||
public class LockOutRealm extends CombinedRealm {
|
||||
|
||||
private static final Log log = LogFactory.getLog(LockOutRealm.class);
|
||||
|
||||
/**
|
||||
* Descriptive information about this Realm implementation.
|
||||
*/
|
||||
protected static final String name = "LockOutRealm";
|
||||
|
||||
/**
|
||||
* The number of times in a row a user has to fail authentication to be
|
||||
* locked out. Defaults to 5.
|
||||
*/
|
||||
protected int failureCount = 5;
|
||||
|
||||
/**
|
||||
* The time (in seconds) a user is locked out for after too many
|
||||
* authentication failures. Defaults to 300 (5 minutes).
|
||||
*/
|
||||
protected int lockOutTime = 300;
|
||||
|
||||
/**
|
||||
* Number of users that have failed authentication to keep in cache. Over
|
||||
* time the cache will grow to this size and may not shrink. Defaults to
|
||||
* 1000.
|
||||
*/
|
||||
protected int cacheSize = 1000;
|
||||
|
||||
/**
|
||||
* If a failed user is removed from the cache because the cache is too big
|
||||
* before it has been in the cache for at least this period of time (in
|
||||
* seconds) a warning message will be logged. Defaults to 3600 (1 hour).
|
||||
*/
|
||||
protected int cacheRemovalWarningTime = 3600;
|
||||
|
||||
/**
|
||||
* Users whose last authentication attempt failed. Entries will be ordered
|
||||
* in access order from least recent to most recent.
|
||||
*/
|
||||
protected Map<String,LockRecord> failedUsers = null;
|
||||
|
||||
|
||||
/**
|
||||
* Prepare for the beginning of active use of the public methods of this
|
||||
* component and implement the requirements of
|
||||
* {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
|
||||
*
|
||||
* @exception LifecycleException if this component detects a fatal error
|
||||
* that prevents this component from being used
|
||||
*/
|
||||
@Override
|
||||
protected synchronized void startInternal() throws LifecycleException {
|
||||
// Configure the list of failed users to delete the oldest entry once it
|
||||
// exceeds the specified size
|
||||
failedUsers = new LinkedHashMap<String, LockRecord>(cacheSize, 0.75f,
|
||||
true) {
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Override
|
||||
protected boolean removeEldestEntry(
|
||||
Map.Entry<String, LockRecord> eldest) {
|
||||
if (size() > cacheSize) {
|
||||
// Check to see if this element has been removed too quickly
|
||||
long timeInCache = (System.currentTimeMillis() -
|
||||
eldest.getValue().getLastFailureTime())/1000;
|
||||
|
||||
if (timeInCache < cacheRemovalWarningTime) {
|
||||
log.warn(sm.getString("lockOutRealm.removeWarning",
|
||||
eldest.getKey(), Long.valueOf(timeInCache)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
super.startInternal();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the Principal associated with the specified username, which
|
||||
* matches the digest calculated using the given parameters using the
|
||||
* method described in RFC 2069; otherwise return <code>null</code>.
|
||||
*
|
||||
* @param username Username of the Principal to look up
|
||||
* @param clientDigest Digest which has been submitted by the client
|
||||
* @param nonce Unique (or supposedly unique) token which has been used
|
||||
* for this request
|
||||
* @param realmName Realm name
|
||||
* @param md5a2 Second MD5 digest used to calculate the digest :
|
||||
* MD5(Method + ":" + uri)
|
||||
*/
|
||||
@Override
|
||||
public Principal authenticate(String username, String clientDigest,
|
||||
String nonce, String nc, String cnonce, String qop,
|
||||
String realmName, String md5a2) {
|
||||
|
||||
Principal authenticatedUser = super.authenticate(username, clientDigest, nonce, nc, cnonce,
|
||||
qop, realmName, md5a2);
|
||||
return filterLockedAccounts(username, authenticatedUser);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the Principal associated with the specified username and
|
||||
* credentials, if there is one; otherwise return <code>null</code>.
|
||||
*
|
||||
* @param username Username of the Principal to look up
|
||||
* @param credentials Password or other credentials to use in
|
||||
* authenticating this username
|
||||
*/
|
||||
@Override
|
||||
public Principal authenticate(String username, String credentials) {
|
||||
Principal authenticatedUser = super.authenticate(username, credentials);
|
||||
return filterLockedAccounts(username, authenticatedUser);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the Principal associated with the specified chain of X509
|
||||
* client certificates. If there is none, return <code>null</code>.
|
||||
*
|
||||
* @param certs Array of client certificates, with the first one in
|
||||
* the array being the certificate of the client itself.
|
||||
*/
|
||||
@Override
|
||||
public Principal authenticate(X509Certificate[] certs) {
|
||||
String username = null;
|
||||
if (certs != null && certs.length >0) {
|
||||
username = certs[0].getSubjectDN().getName();
|
||||
}
|
||||
|
||||
Principal authenticatedUser = super.authenticate(certs);
|
||||
return filterLockedAccounts(username, authenticatedUser);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Principal authenticate(GSSContext gssContext, boolean storeCreds) {
|
||||
if (gssContext.isEstablished()) {
|
||||
String username = null;
|
||||
GSSName name = null;
|
||||
try {
|
||||
name = gssContext.getSrcName();
|
||||
} catch (GSSException e) {
|
||||
log.warn(sm.getString("realmBase.gssNameFail"), e);
|
||||
return null;
|
||||
}
|
||||
|
||||
username = name.toString();
|
||||
|
||||
Principal authenticatedUser = super.authenticate(gssContext, storeCreds);
|
||||
|
||||
return filterLockedAccounts(username, authenticatedUser);
|
||||
}
|
||||
|
||||
// Fail in all other cases
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Principal authenticate(GSSName gssName, GSSCredential gssCredential) {
|
||||
String username = gssName.toString();
|
||||
|
||||
Principal authenticatedUser = super.authenticate(gssName, gssCredential);
|
||||
|
||||
return filterLockedAccounts(username, authenticatedUser);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Filters authenticated principals to ensure that <code>null</code> is
|
||||
* returned for any user that is currently locked out.
|
||||
*/
|
||||
private Principal filterLockedAccounts(String username, Principal authenticatedUser) {
|
||||
// Register all failed authentications
|
||||
if (authenticatedUser == null && isAvailable()) {
|
||||
registerAuthFailure(username);
|
||||
}
|
||||
|
||||
if (isLocked(username)) {
|
||||
// If the user is currently locked, authentication will always fail
|
||||
log.warn(sm.getString("lockOutRealm.authLockedUser", username));
|
||||
return null;
|
||||
}
|
||||
|
||||
if (authenticatedUser != null) {
|
||||
registerAuthSuccess(username);
|
||||
}
|
||||
|
||||
return authenticatedUser;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unlock the specified username. This will remove all records of
|
||||
* authentication failures for this user.
|
||||
*
|
||||
* @param username The user to unlock
|
||||
*/
|
||||
public void unlock(String username) {
|
||||
// Auth success clears the lock record so...
|
||||
registerAuthSuccess(username);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks to see if the current user is locked. If this is associated with
|
||||
* a login attempt, then the last access time will be recorded and any
|
||||
* attempt to authenticated a locked user will log a warning.
|
||||
*/
|
||||
public boolean isLocked(String username) {
|
||||
LockRecord lockRecord = null;
|
||||
synchronized (this) {
|
||||
lockRecord = failedUsers.get(username);
|
||||
}
|
||||
|
||||
// No lock record means user can't be locked
|
||||
if (lockRecord == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check to see if user is locked
|
||||
if (lockRecord.getFailures() >= failureCount &&
|
||||
(System.currentTimeMillis() -
|
||||
lockRecord.getLastFailureTime())/1000 < lockOutTime) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// User has not, yet, exceeded lock thresholds
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* After successful authentication, any record of previous authentication
|
||||
* failure is removed.
|
||||
*/
|
||||
private synchronized void registerAuthSuccess(String username) {
|
||||
// Successful authentication means removal from the list of failed users
|
||||
failedUsers.remove(username);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* After a failed authentication, add the record of the failed
|
||||
* authentication.
|
||||
*/
|
||||
private void registerAuthFailure(String username) {
|
||||
LockRecord lockRecord = null;
|
||||
synchronized (this) {
|
||||
if (!failedUsers.containsKey(username)) {
|
||||
lockRecord = new LockRecord();
|
||||
failedUsers.put(username, lockRecord);
|
||||
} else {
|
||||
lockRecord = failedUsers.get(username);
|
||||
if (lockRecord.getFailures() >= failureCount &&
|
||||
((System.currentTimeMillis() -
|
||||
lockRecord.getLastFailureTime())/1000)
|
||||
> lockOutTime) {
|
||||
// User was previously locked out but lockout has now
|
||||
// expired so reset failure count
|
||||
lockRecord.setFailures(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
lockRecord.registerFailure();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the number of failed authentication attempts required to lock the
|
||||
* user account.
|
||||
* @return the failureCount
|
||||
*/
|
||||
public int getFailureCount() {
|
||||
return failureCount;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the number of failed authentication attempts required to lock the
|
||||
* user account.
|
||||
* @param failureCount the failureCount to set
|
||||
*/
|
||||
public void setFailureCount(int failureCount) {
|
||||
this.failureCount = failureCount;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the period for which an account will be locked.
|
||||
* @return the lockOutTime
|
||||
*/
|
||||
public int getLockOutTime() {
|
||||
return lockOutTime;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the period for which an account will be locked.
|
||||
* @param lockOutTime the lockOutTime to set
|
||||
*/
|
||||
public void setLockOutTime(int lockOutTime) {
|
||||
this.lockOutTime = lockOutTime;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the maximum number of users for which authentication failure will be
|
||||
* kept in the cache.
|
||||
* @return the cacheSize
|
||||
*/
|
||||
public int getCacheSize() {
|
||||
return cacheSize;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the maximum number of users for which authentication failure will be
|
||||
* kept in the cache.
|
||||
* @param cacheSize the cacheSize to set
|
||||
*/
|
||||
public void setCacheSize(int cacheSize) {
|
||||
this.cacheSize = cacheSize;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the minimum period a failed authentication must remain in the cache
|
||||
* to avoid generating a warning if it is removed from the cache to make
|
||||
* space for a new entry.
|
||||
* @return the cacheRemovalWarningTime
|
||||
*/
|
||||
public int getCacheRemovalWarningTime() {
|
||||
return cacheRemovalWarningTime;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the minimum period a failed authentication must remain in the cache
|
||||
* to avoid generating a warning if it is removed from the cache to make
|
||||
* space for a new entry.
|
||||
* @param cacheRemovalWarningTime the cacheRemovalWarningTime to set
|
||||
*/
|
||||
public void setCacheRemovalWarningTime(int cacheRemovalWarningTime) {
|
||||
this.cacheRemovalWarningTime = cacheRemovalWarningTime;
|
||||
}
|
||||
|
||||
|
||||
protected static class LockRecord {
|
||||
private final AtomicInteger failures = new AtomicInteger(0);
|
||||
private long lastFailureTime = 0;
|
||||
|
||||
public int getFailures() {
|
||||
return failures.get();
|
||||
}
|
||||
|
||||
public void setFailures(int theFailures) {
|
||||
failures.set(theFailures);
|
||||
}
|
||||
|
||||
public long getLastFailureTime() {
|
||||
return lastFailureTime;
|
||||
}
|
||||
|
||||
public void registerFailure() {
|
||||
failures.incrementAndGet();
|
||||
lastFailureTime = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
}
|
||||
279
java/org/apache/catalina/realm/MemoryRealm.java
Normal file
279
java/org/apache/catalina/realm/MemoryRealm.java
Normal file
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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 org.apache.catalina.realm;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.Principal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.digester.Digester;
|
||||
import org.apache.tomcat.util.file.ConfigFileLoader;
|
||||
|
||||
|
||||
/**
|
||||
* Simple implementation of <b>Realm</b> that reads an XML file to configure
|
||||
* the valid users, passwords, and roles. The file format (and default file
|
||||
* location) are identical to those currently supported by Tomcat 3.X.
|
||||
* <p>
|
||||
* <strong>IMPLEMENTATION NOTE</strong>: It is assumed that the in-memory
|
||||
* collection representing our defined users (and their roles) is initialized
|
||||
* at application startup and never modified again. Therefore, no thread
|
||||
* synchronization is performed around accesses to the principals collection.
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
*/
|
||||
public class MemoryRealm extends RealmBase {
|
||||
|
||||
private static final Log log = LogFactory.getLog(MemoryRealm.class);
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
|
||||
/**
|
||||
* The Digester we will use to process in-memory database files.
|
||||
*/
|
||||
private static Digester digester = null;
|
||||
|
||||
|
||||
/**
|
||||
* Descriptive information about this Realm implementation.
|
||||
* @deprecated This will be removed in Tomcat 9 onwards.
|
||||
*/
|
||||
@Deprecated
|
||||
protected static final String name = "MemoryRealm";
|
||||
|
||||
|
||||
/**
|
||||
* The pathname (absolute or relative to Catalina's current working
|
||||
* directory) of the XML file containing our database information.
|
||||
*/
|
||||
private String pathname = "conf/tomcat-users.xml";
|
||||
|
||||
|
||||
/**
|
||||
* The set of valid Principals for this Realm, keyed by user name.
|
||||
*/
|
||||
private final Map<String,GenericPrincipal> principals = new HashMap<>();
|
||||
|
||||
|
||||
// ------------------------------------------------------------- Properties
|
||||
|
||||
/**
|
||||
* @return the pathname of our XML file containing user definitions.
|
||||
*/
|
||||
public String getPathname() {
|
||||
|
||||
return pathname;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the pathname of our XML file containing user definitions. If a
|
||||
* relative pathname is specified, it is resolved against "catalina.base".
|
||||
*
|
||||
* @param pathname The new pathname
|
||||
*/
|
||||
public void setPathname(String pathname) {
|
||||
|
||||
this.pathname = pathname;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
|
||||
/**
|
||||
* Return the Principal associated with the specified username and
|
||||
* credentials, if there is one; otherwise return <code>null</code>.
|
||||
*
|
||||
* @param username Username of the Principal to look up
|
||||
* @param credentials Password or other credentials to use in
|
||||
* authenticating this username
|
||||
* @return the associated principal, or <code>null</code> if there is none.
|
||||
*/
|
||||
@Override
|
||||
public Principal authenticate(String username, String credentials) {
|
||||
|
||||
// No user or no credentials
|
||||
// Can't possibly authenticate, don't bother the database then
|
||||
if (username == null || credentials == null) {
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("memoryRealm.authenticateFailure", username));
|
||||
return null;
|
||||
}
|
||||
|
||||
GenericPrincipal principal = principals.get(username);
|
||||
|
||||
if(principal == null || principal.getPassword() == null) {
|
||||
// User was not found in the database or the password was null
|
||||
// Waste a bit of time as not to reveal that the user does not exist.
|
||||
getCredentialHandler().mutate(credentials);
|
||||
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("memoryRealm.authenticateFailure", username));
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean validated = getCredentialHandler().matches(credentials, principal.getPassword());
|
||||
|
||||
if (validated) {
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("memoryRealm.authenticateSuccess", username));
|
||||
return principal;
|
||||
} else {
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("memoryRealm.authenticateFailure", username));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------- Package Methods
|
||||
|
||||
|
||||
/**
|
||||
* Add a new user to the in-memory database.
|
||||
*
|
||||
* @param username User's username
|
||||
* @param password User's password (clear text)
|
||||
* @param roles Comma-delimited set of roles associated with this user
|
||||
*/
|
||||
void addUser(String username, String password, String roles) {
|
||||
|
||||
// Accumulate the list of roles for this user
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
roles += ",";
|
||||
while (true) {
|
||||
int comma = roles.indexOf(',');
|
||||
if (comma < 0)
|
||||
break;
|
||||
String role = roles.substring(0, comma).trim();
|
||||
list.add(role);
|
||||
roles = roles.substring(comma + 1);
|
||||
}
|
||||
|
||||
// Construct and cache the Principal for this user
|
||||
GenericPrincipal principal =
|
||||
new GenericPrincipal(username, password, list);
|
||||
principals.put(username, principal);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------ Protected Methods
|
||||
|
||||
|
||||
/**
|
||||
* @return a configured <code>Digester</code> to use for processing
|
||||
* the XML input file, creating a new one if necessary.
|
||||
*/
|
||||
protected synchronized Digester getDigester() {
|
||||
if (digester == null) {
|
||||
digester = new Digester();
|
||||
digester.setValidating(false);
|
||||
try {
|
||||
digester.setFeature(
|
||||
"http://apache.org/xml/features/allow-java-encodings",
|
||||
true);
|
||||
} catch (Exception e) {
|
||||
log.warn(sm.getString("memoryRealm.xmlFeatureEncoding"), e);
|
||||
}
|
||||
digester.addRuleSet(new MemoryRuleSet());
|
||||
}
|
||||
return digester;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
protected String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the password associated with the given principal's user name.
|
||||
*/
|
||||
@Override
|
||||
protected String getPassword(String username) {
|
||||
|
||||
GenericPrincipal principal = principals.get(username);
|
||||
if (principal != null) {
|
||||
return principal.getPassword();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the Principal associated with the given user name.
|
||||
*/
|
||||
@Override
|
||||
protected Principal getPrincipal(String username) {
|
||||
|
||||
return principals.get(username);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------ Lifecycle Methods
|
||||
|
||||
/**
|
||||
* Prepare for the beginning of active use of the public methods of this
|
||||
* component and implement the requirements of
|
||||
* {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
|
||||
*
|
||||
* @exception LifecycleException if this component detects a fatal error
|
||||
* that prevents this component from being used
|
||||
*/
|
||||
@Override
|
||||
protected void startInternal() throws LifecycleException {
|
||||
String pathName = getPathname();
|
||||
try (InputStream is = ConfigFileLoader.getInputStream(pathName)) {
|
||||
// Load the contents of the database file
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("memoryRealm.loadPath", pathName));
|
||||
}
|
||||
|
||||
Digester digester = getDigester();
|
||||
try {
|
||||
synchronized (digester) {
|
||||
digester.push(this);
|
||||
digester.parse(is);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new LifecycleException(sm.getString("memoryRealm.readXml"), e);
|
||||
} finally {
|
||||
digester.reset();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new LifecycleException(sm.getString("memoryRealm.loadExist", pathName), ioe);
|
||||
}
|
||||
|
||||
super.startInternal();
|
||||
}
|
||||
}
|
||||
134
java/org/apache/catalina/realm/MemoryRuleSet.java
Normal file
134
java/org/apache/catalina/realm/MemoryRuleSet.java
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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 org.apache.catalina.realm;
|
||||
|
||||
|
||||
import org.apache.tomcat.util.digester.Digester;
|
||||
import org.apache.tomcat.util.digester.Rule;
|
||||
import org.apache.tomcat.util.digester.RuleSetBase;
|
||||
import org.xml.sax.Attributes;
|
||||
|
||||
|
||||
/**
|
||||
* <p><strong>RuleSet</strong> for recognizing the users defined in the
|
||||
* XML file processed by <code>MemoryRealm</code>.</p>
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class MemoryRuleSet extends RuleSetBase {
|
||||
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
|
||||
/**
|
||||
* The matching pattern prefix to use for recognizing our elements.
|
||||
*/
|
||||
protected final String prefix;
|
||||
|
||||
|
||||
// ------------------------------------------------------------ Constructor
|
||||
|
||||
|
||||
/**
|
||||
* Construct an instance of this <code>RuleSet</code> with the default
|
||||
* matching pattern prefix.
|
||||
*/
|
||||
public MemoryRuleSet() {
|
||||
|
||||
this("tomcat-users/");
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct an instance of this <code>RuleSet</code> with the specified
|
||||
* matching pattern prefix.
|
||||
*
|
||||
* @param prefix Prefix for matching pattern rules (including the
|
||||
* trailing slash character)
|
||||
*/
|
||||
public MemoryRuleSet(String prefix) {
|
||||
super();
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
|
||||
/**
|
||||
* <p>Add the set of Rule instances defined in this RuleSet to the
|
||||
* specified <code>Digester</code> instance, associating them with
|
||||
* our namespace URI (if any). This method should only be called
|
||||
* by a Digester instance.</p>
|
||||
*
|
||||
* @param digester Digester instance to which the new Rule instances
|
||||
* should be added.
|
||||
*/
|
||||
@Override
|
||||
public void addRuleInstances(Digester digester) {
|
||||
|
||||
digester.addRule(prefix + "user", new MemoryUserRule());
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Private class used when parsing the XML database file.
|
||||
*/
|
||||
final class MemoryUserRule extends Rule {
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new instance of this <code>Rule</code>.
|
||||
*/
|
||||
public MemoryUserRule() {
|
||||
// No initialisation required
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process a <code><user></code> element from the XML database file.
|
||||
*
|
||||
* @param attributes The attribute list for this element
|
||||
*/
|
||||
@Override
|
||||
public void begin(String namespace, String name, Attributes attributes)
|
||||
throws Exception {
|
||||
|
||||
String username = attributes.getValue("username");
|
||||
if (username == null) {
|
||||
username = attributes.getValue("name");
|
||||
}
|
||||
String password = attributes.getValue("password");
|
||||
String roles = attributes.getValue("roles");
|
||||
|
||||
MemoryRealm realm =
|
||||
(MemoryRealm) digester.peek(digester.getCount() - 1);
|
||||
realm.addUser(username, password, roles);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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 org.apache.catalina.realm;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.buf.B2CConverter;
|
||||
import org.apache.tomcat.util.buf.HexUtils;
|
||||
import org.apache.tomcat.util.codec.binary.Base64;
|
||||
import org.apache.tomcat.util.security.ConcurrentMessageDigest;
|
||||
|
||||
/**
|
||||
* This credential handler supports the following forms of stored passwords:
|
||||
* <ul>
|
||||
* <li><b>encodedCredential</b> - a hex encoded digest of the password digested
|
||||
* using the configured digest</li>
|
||||
* <li><b>{MD5}encodedCredential</b> - a Base64 encoded MD5 digest of the
|
||||
* password</li>
|
||||
* <li><b>{SHA}encodedCredential</b> - a Base64 encoded SHA1 digest of the
|
||||
* password</li>
|
||||
* <li><b>{SSHA}encodedCredential</b> - 20 character salt followed by the salted
|
||||
* SHA1 digest Base64 encoded</li>
|
||||
* <li><b>salt$iterationCount$encodedCredential</b> - a hex encoded salt,
|
||||
* iteration code and a hex encoded credential, each separated by $</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* If the stored password form does not include an iteration count then an
|
||||
* iteration count of 1 is used.
|
||||
* <p>
|
||||
* If the stored password form does not include salt then no salt is used.
|
||||
*/
|
||||
public class MessageDigestCredentialHandler extends DigestCredentialHandlerBase {
|
||||
|
||||
private static final Log log = LogFactory.getLog(MessageDigestCredentialHandler.class);
|
||||
|
||||
public static final int DEFAULT_ITERATIONS = 1;
|
||||
|
||||
private Charset encoding = StandardCharsets.UTF_8;
|
||||
private String algorithm = null;
|
||||
|
||||
|
||||
public String getEncoding() {
|
||||
return encoding.name();
|
||||
}
|
||||
|
||||
|
||||
public void setEncoding(String encodingName) {
|
||||
if (encodingName == null) {
|
||||
encoding = StandardCharsets.UTF_8;
|
||||
} else {
|
||||
try {
|
||||
this.encoding = B2CConverter.getCharset(encodingName);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
log.warn(sm.getString("mdCredentialHandler.unknownEncoding",
|
||||
encodingName, encoding.name()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getAlgorithm() {
|
||||
return algorithm;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setAlgorithm(String algorithm) throws NoSuchAlgorithmException {
|
||||
ConcurrentMessageDigest.init(algorithm);
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean matches(String inputCredentials, String storedCredentials) {
|
||||
|
||||
if (inputCredentials == null || storedCredentials == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getAlgorithm() == null) {
|
||||
// No digests, compare directly
|
||||
return storedCredentials.equals(inputCredentials);
|
||||
} else {
|
||||
// Some directories and databases prefix the password with the hash
|
||||
// type. The string is in a format compatible with Base64.encode not
|
||||
// the normal hex encoding of the digest
|
||||
if (storedCredentials.startsWith("{MD5}") ||
|
||||
storedCredentials.startsWith("{SHA}")) {
|
||||
// Server is storing digested passwords with a prefix indicating
|
||||
// the digest type
|
||||
String serverDigest = storedCredentials.substring(5);
|
||||
String userDigest = Base64.encodeBase64String(ConcurrentMessageDigest.digest(
|
||||
getAlgorithm(), inputCredentials.getBytes(StandardCharsets.ISO_8859_1)));
|
||||
return userDigest.equals(serverDigest);
|
||||
|
||||
} else if (storedCredentials.startsWith("{SSHA}")) {
|
||||
// Server is storing digested passwords with a prefix indicating
|
||||
// the digest type and the salt used when creating that digest
|
||||
|
||||
String serverDigestPlusSalt = storedCredentials.substring(6);
|
||||
|
||||
// Need to convert the salt to bytes to apply it to the user's
|
||||
// digested password.
|
||||
byte[] serverDigestPlusSaltBytes =
|
||||
Base64.decodeBase64(serverDigestPlusSalt);
|
||||
final int saltPos = 20;
|
||||
byte[] serverDigestBytes = new byte[saltPos];
|
||||
System.arraycopy(serverDigestPlusSaltBytes, 0,
|
||||
serverDigestBytes, 0, saltPos);
|
||||
final int saltLength = serverDigestPlusSaltBytes.length - saltPos;
|
||||
byte[] serverSaltBytes = new byte[saltLength];
|
||||
System.arraycopy(serverDigestPlusSaltBytes, saltPos,
|
||||
serverSaltBytes, 0, saltLength);
|
||||
|
||||
// Generate the digested form of the user provided password
|
||||
// using the salt
|
||||
byte[] userDigestBytes = ConcurrentMessageDigest.digest(getAlgorithm(),
|
||||
inputCredentials.getBytes(StandardCharsets.ISO_8859_1),
|
||||
serverSaltBytes);
|
||||
|
||||
return Arrays.equals(userDigestBytes, serverDigestBytes);
|
||||
|
||||
} else if (storedCredentials.indexOf('$') > -1) {
|
||||
return matchesSaltIterationsEncoded(inputCredentials, storedCredentials);
|
||||
|
||||
} else {
|
||||
// Hex hashes should be compared case-insensitively
|
||||
String userDigest = mutate(inputCredentials, null, 1);
|
||||
if (userDigest == null) {
|
||||
// Failed to mutate user credentials. Automatic fail.
|
||||
// Root cause should be logged by mutate()
|
||||
return false;
|
||||
}
|
||||
return storedCredentials.equalsIgnoreCase(userDigest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String mutate(String inputCredentials, byte[] salt, int iterations) {
|
||||
if (algorithm == null) {
|
||||
return inputCredentials;
|
||||
} else {
|
||||
byte[] userDigest;
|
||||
if (salt == null) {
|
||||
userDigest = ConcurrentMessageDigest.digest(algorithm, iterations,
|
||||
inputCredentials.getBytes(encoding));
|
||||
} else {
|
||||
userDigest = ConcurrentMessageDigest.digest(algorithm, iterations,
|
||||
salt, inputCredentials.getBytes(encoding));
|
||||
}
|
||||
return HexUtils.toHexString(userDigest);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected int getDefaultIterations() {
|
||||
return DEFAULT_ITERATIONS;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Log getLog() {
|
||||
return log;
|
||||
}
|
||||
}
|
||||
65
java/org/apache/catalina/realm/NestedCredentialHandler.java
Normal file
65
java/org/apache/catalina/realm/NestedCredentialHandler.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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 org.apache.catalina.realm;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.catalina.CredentialHandler;
|
||||
|
||||
public class NestedCredentialHandler implements CredentialHandler {
|
||||
|
||||
private final List<CredentialHandler> credentialHandlers = new ArrayList<>();
|
||||
|
||||
|
||||
@Override
|
||||
public boolean matches(String inputCredentials, String storedCredentials) {
|
||||
for (CredentialHandler handler : credentialHandlers) {
|
||||
if (handler.matches(inputCredentials, storedCredentials)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The input credentials will be passed to the first nested
|
||||
* {@link CredentialHandler}. If no nested {@link CredentialHandler} are
|
||||
* configured then <code>null</code> will be returned.
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String mutate(String inputCredentials) {
|
||||
if (credentialHandlers.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return credentialHandlers.get(0).mutate(inputCredentials);
|
||||
}
|
||||
|
||||
|
||||
public void addCredentialHandler(CredentialHandler handler) {
|
||||
credentialHandlers.add(handler);
|
||||
}
|
||||
|
||||
public CredentialHandler[] getCredentialHandlers() {
|
||||
return credentialHandlers.toArray(new CredentialHandler[0]);
|
||||
}
|
||||
|
||||
}
|
||||
47
java/org/apache/catalina/realm/NullRealm.java
Normal file
47
java/org/apache/catalina/realm/NullRealm.java
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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 org.apache.catalina.realm;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
/**
|
||||
* Minimal Realm implementation that always returns null when an attempt is made
|
||||
* to validate a user name and password. It is intended to be used as a default
|
||||
* Realm implementation when no other Realm is specified.
|
||||
*/
|
||||
public class NullRealm extends RealmBase {
|
||||
|
||||
private static final String NAME = "NullRealm";
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
protected String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPassword(String username) {
|
||||
// Always return null
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Principal getPrincipal(String username) {
|
||||
// Always return null
|
||||
return null;
|
||||
}
|
||||
}
|
||||
1635
java/org/apache/catalina/realm/RealmBase.java
Normal file
1635
java/org/apache/catalina/realm/RealmBase.java
Normal file
File diff suppressed because it is too large
Load Diff
105
java/org/apache/catalina/realm/SecretKeyCredentialHandler.java
Normal file
105
java/org/apache/catalina/realm/SecretKeyCredentialHandler.java
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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 org.apache.catalina.realm;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.KeySpec;
|
||||
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.buf.HexUtils;
|
||||
|
||||
public class SecretKeyCredentialHandler extends DigestCredentialHandlerBase {
|
||||
|
||||
private static final Log log = LogFactory.getLog(SecretKeyCredentialHandler.class);
|
||||
|
||||
public static final String DEFAULT_ALGORITHM = "PBKDF2WithHmacSHA1";
|
||||
public static final int DEFAULT_KEY_LENGTH = 160;
|
||||
public static final int DEFAULT_ITERATIONS = 20000;
|
||||
|
||||
|
||||
private SecretKeyFactory secretKeyFactory;
|
||||
private int keyLength = DEFAULT_KEY_LENGTH;
|
||||
|
||||
|
||||
public SecretKeyCredentialHandler() throws NoSuchAlgorithmException {
|
||||
setAlgorithm(DEFAULT_ALGORITHM);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getAlgorithm() {
|
||||
return secretKeyFactory.getAlgorithm();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setAlgorithm(String algorithm) throws NoSuchAlgorithmException {
|
||||
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(algorithm);
|
||||
this.secretKeyFactory = secretKeyFactory;
|
||||
}
|
||||
|
||||
|
||||
public int getKeyLength() {
|
||||
return keyLength;
|
||||
}
|
||||
|
||||
|
||||
public void setKeyLength(int keyLength) {
|
||||
this.keyLength = keyLength;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean matches(String inputCredentials, String storedCredentials) {
|
||||
return matchesSaltIterationsEncoded(inputCredentials, storedCredentials);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String mutate(String inputCredentials, byte[] salt, int iterations) {
|
||||
return mutate(inputCredentials, salt, iterations, getKeyLength());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String mutate(String inputCredentials, byte[] salt, int iterations, int keyLength) {
|
||||
try {
|
||||
KeySpec spec = new PBEKeySpec(inputCredentials.toCharArray(), salt, iterations, keyLength);
|
||||
return HexUtils.toHexString(secretKeyFactory.generateSecret(spec).getEncoded());
|
||||
} catch (InvalidKeySpecException | IllegalArgumentException e) {
|
||||
log.warn(sm.getString("pbeCredentialHandler.invalidKeySpec"), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected int getDefaultIterations() {
|
||||
return DEFAULT_ITERATIONS;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Log getLog() {
|
||||
return log;
|
||||
}
|
||||
}
|
||||
257
java/org/apache/catalina/realm/UserDatabaseRealm.java
Normal file
257
java/org/apache/catalina/realm/UserDatabaseRealm.java
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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 org.apache.catalina.realm;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.naming.Context;
|
||||
|
||||
import org.apache.catalina.Group;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.Role;
|
||||
import org.apache.catalina.User;
|
||||
import org.apache.catalina.UserDatabase;
|
||||
import org.apache.catalina.Wrapper;
|
||||
import org.apache.catalina.users.MemoryUserDatabase;
|
||||
import org.apache.tomcat.util.ExceptionUtils;
|
||||
|
||||
/**
|
||||
* Implementation of {@link org.apache.catalina.Realm} that is based on an
|
||||
* implementation of {@link UserDatabase} made available through the global JNDI
|
||||
* resources configured for this instance of Catalina. Set the
|
||||
* <code>resourceName</code> parameter to the global JNDI resources name for the
|
||||
* configured instance of <code>UserDatabase</code> that we should consult.
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
* @since 4.1
|
||||
*/
|
||||
public class UserDatabaseRealm extends RealmBase {
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
/**
|
||||
* The <code>UserDatabase</code> we will use to authenticate users and
|
||||
* identify associated roles.
|
||||
*/
|
||||
protected UserDatabase database = null;
|
||||
|
||||
/**
|
||||
* Descriptive information about this Realm implementation.
|
||||
* @deprecated This will be removed in Tomcat 9 onwards.
|
||||
*/
|
||||
@Deprecated
|
||||
protected static final String name = "UserDatabaseRealm";
|
||||
|
||||
|
||||
/**
|
||||
* The global JNDI name of the <code>UserDatabase</code> resource we will be
|
||||
* utilizing.
|
||||
*/
|
||||
protected String resourceName = "UserDatabase";
|
||||
|
||||
|
||||
// ------------------------------------------------------------- Properties
|
||||
|
||||
/**
|
||||
* @return the global JNDI name of the <code>UserDatabase</code> resource we
|
||||
* will be using.
|
||||
*/
|
||||
public String getResourceName() {
|
||||
return resourceName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the global JNDI name of the <code>UserDatabase</code> resource we
|
||||
* will be using.
|
||||
*
|
||||
* @param resourceName The new global JNDI name
|
||||
*/
|
||||
public void setResourceName(String resourceName) {
|
||||
this.resourceName = resourceName;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
/**
|
||||
* Return <code>true</code> if the specified Principal has the specified
|
||||
* security role, within the context of this Realm; otherwise return
|
||||
* <code>false</code>. This implementation returns <code>true</code> if the
|
||||
* <code>User</code> has the role, or if any <code>Group</code> that the
|
||||
* <code>User</code> is a member of has the role.
|
||||
*
|
||||
* @param principal Principal for whom the role is to be checked
|
||||
* @param role Security role to be checked
|
||||
*/
|
||||
@Override
|
||||
public boolean hasRole(Wrapper wrapper, Principal principal, String role) {
|
||||
// Check for a role alias defined in a <security-role-ref> element
|
||||
if (wrapper != null) {
|
||||
String realRole = wrapper.findSecurityReference(role);
|
||||
if (realRole != null)
|
||||
role = realRole;
|
||||
}
|
||||
if (principal instanceof GenericPrincipal) {
|
||||
GenericPrincipal gp = (GenericPrincipal) principal;
|
||||
if (gp.getUserPrincipal() instanceof User) {
|
||||
principal = gp.getUserPrincipal();
|
||||
}
|
||||
}
|
||||
if (!(principal instanceof User)) {
|
||||
// Play nice with SSO and mixed Realms
|
||||
// No need to pass the wrapper here because role mapping has been
|
||||
// performed already a few lines above
|
||||
return super.hasRole(null, principal, role);
|
||||
}
|
||||
if ("*".equals(role)) {
|
||||
return true;
|
||||
} else if (role == null) {
|
||||
return false;
|
||||
}
|
||||
User user = (User) principal;
|
||||
Role dbrole = database.findRole(role);
|
||||
if (dbrole == null) {
|
||||
return false;
|
||||
}
|
||||
if (user.isInRole(dbrole)) {
|
||||
return true;
|
||||
}
|
||||
Iterator<Group> groups = user.getGroups();
|
||||
while (groups.hasNext()) {
|
||||
Group group = groups.next();
|
||||
if (group.isInRole(dbrole)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------ Protected Methods
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
protected String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void backgroundProcess() {
|
||||
if (database instanceof MemoryUserDatabase) {
|
||||
((MemoryUserDatabase) database).backgroundProcess();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the password associated with the given principal's user name.
|
||||
*/
|
||||
@Override
|
||||
protected String getPassword(String username) {
|
||||
User user = database.findUser(username);
|
||||
|
||||
if (user == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return user.getPassword();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the Principal associated with the given user name.
|
||||
*/
|
||||
@Override
|
||||
protected Principal getPrincipal(String username) {
|
||||
|
||||
User user = database.findUser(username);
|
||||
if (user == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<String> roles = new ArrayList<>();
|
||||
Iterator<Role> uroles = user.getRoles();
|
||||
while (uroles.hasNext()) {
|
||||
Role role = uroles.next();
|
||||
roles.add(role.getName());
|
||||
}
|
||||
Iterator<Group> groups = user.getGroups();
|
||||
while (groups.hasNext()) {
|
||||
Group group = groups.next();
|
||||
uroles = group.getRoles();
|
||||
while (uroles.hasNext()) {
|
||||
Role role = uroles.next();
|
||||
roles.add(role.getName());
|
||||
}
|
||||
}
|
||||
return new GenericPrincipal(username, user.getPassword(), roles, user);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------ Lifecycle Methods
|
||||
|
||||
/**
|
||||
* Prepare for the beginning of active use of the public methods of this
|
||||
* component and implement the requirements of
|
||||
* {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
|
||||
*
|
||||
* @exception LifecycleException if this component detects a fatal error
|
||||
* that prevents this component from being used
|
||||
*/
|
||||
@Override
|
||||
protected void startInternal() throws LifecycleException {
|
||||
|
||||
try {
|
||||
Context context = getServer().getGlobalNamingContext();
|
||||
database = (UserDatabase) context.lookup(resourceName);
|
||||
} catch (Throwable e) {
|
||||
ExceptionUtils.handleThrowable(e);
|
||||
containerLog.error(sm.getString("userDatabaseRealm.lookup", resourceName), e);
|
||||
database = null;
|
||||
}
|
||||
if (database == null) {
|
||||
throw new LifecycleException(
|
||||
sm.getString("userDatabaseRealm.noDatabase", resourceName));
|
||||
}
|
||||
|
||||
super.startInternal();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gracefully terminate the active use of the public methods of this
|
||||
* component and implement the requirements of
|
||||
* {@link org.apache.catalina.util.LifecycleBase#stopInternal()}.
|
||||
*
|
||||
* @exception LifecycleException if this component detects a fatal error
|
||||
* that needs to be reported
|
||||
*/
|
||||
@Override
|
||||
protected void stopInternal() throws LifecycleException {
|
||||
|
||||
// Perform normal superclass finalization
|
||||
super.stopInternal();
|
||||
|
||||
// Release reference to our user database
|
||||
database = null;
|
||||
}
|
||||
}
|
||||
31
java/org/apache/catalina/realm/X509SubjectDnRetriever.java
Normal file
31
java/org/apache/catalina/realm/X509SubjectDnRetriever.java
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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 org.apache.catalina.realm;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
/**
|
||||
* An X509UsernameRetriever that returns a certificate's entire
|
||||
* SubjectDN as the username.
|
||||
*/
|
||||
public class X509SubjectDnRetriever implements X509UsernameRetriever {
|
||||
|
||||
@Override
|
||||
public String getUsername(X509Certificate clientCert) {
|
||||
return clientCert.getSubjectDN().getName();
|
||||
}
|
||||
}
|
||||
33
java/org/apache/catalina/realm/X509UsernameRetriever.java
Normal file
33
java/org/apache/catalina/realm/X509UsernameRetriever.java
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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 org.apache.catalina.realm;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
/**
|
||||
* Provides an interface for retrieving a user name from an X509Certificate.
|
||||
*/
|
||||
public interface X509UsernameRetriever {
|
||||
/**
|
||||
* Gets a user name from an X509Certificate.
|
||||
*
|
||||
* @param cert The certificate containing the user name.
|
||||
* @return An appropriate user name obtained from one or more fields
|
||||
* in the certificate.
|
||||
*/
|
||||
public String getUsername(X509Certificate cert);
|
||||
}
|
||||
547
java/org/apache/catalina/realm/mbeans-descriptors.xml
Normal file
547
java/org/apache/catalina/realm/mbeans-descriptors.xml
Normal file
@@ -0,0 +1,547 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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.
|
||||
-->
|
||||
<mbeans-descriptors>
|
||||
|
||||
<mbean name="DataSourceRealm"
|
||||
className="org.apache.catalina.mbeans.ClassNameMBean"
|
||||
description="Implementation of Realm that works with any JNDI configured DataSource"
|
||||
domain="Catalina"
|
||||
group="Realm"
|
||||
type="org.apache.catalina.realm.DataSourceRealm">
|
||||
|
||||
<attribute name="allRolesMode"
|
||||
description="The all roles mode."
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="className"
|
||||
description="Fully qualified class name of the managed object"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="dataSourceName"
|
||||
description="The JNDI named JDBC DataSource for your database"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="localDataSource"
|
||||
description="Configures if the DataSource is local to the webapp"
|
||||
type="boolean"/>
|
||||
|
||||
<attribute name="realmPath"
|
||||
description="The realm path"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="roleNameCol"
|
||||
description="The column in the user role table that names a role"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="stateName"
|
||||
description="The name of the LifecycleState that this component is currently in"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="userCredCol"
|
||||
description="The column in the user table that holds the user's credentials"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="userNameCol"
|
||||
description="The column in the user table that holds the user's username"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="userRoleTable"
|
||||
description="The table that holds the relation between user's and roles"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="userTable"
|
||||
description="The table that holds user data"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="validate"
|
||||
description="The 'validate certificate chains' flag."
|
||||
type="boolean"/>
|
||||
|
||||
|
||||
<operation name="start" description="Start" impact="ACTION" returnType="void" />
|
||||
<operation name="stop" description="Stop" impact="ACTION" returnType="void" />
|
||||
<operation name="init" description="Init" impact="ACTION" returnType="void" />
|
||||
<operation name="destroy" description="Destroy" impact="ACTION" returnType="void" />
|
||||
|
||||
</mbean>
|
||||
|
||||
<mbean name="JAASRealm"
|
||||
description="Implementation of Realm that authenticates users via the Java Authentication and Authorization Service (JAAS)"
|
||||
domain="Catalina"
|
||||
group="Realm"
|
||||
type="org.apache.catalina.realm.JAASRealm">
|
||||
|
||||
<attribute name="allRolesMode"
|
||||
description="The all roles mode."
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="appName"
|
||||
description="The application name passed to the JAAS LoginContext, which uses it to select the set of relevant LoginModules"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="className"
|
||||
description="Fully qualified class name of the managed object"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="roleClassNames"
|
||||
description="Comma-delimited list of javax.security.Principal classes that represent security roles"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="realmPath"
|
||||
description="The realm path"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="stateName"
|
||||
description="The name of the LifecycleState that this component is currently in"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="userClassNames"
|
||||
description="Comma-delimited list of javax.security.Principal classes that represent individual users"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="useContextClassLoader"
|
||||
description="Sets whether to use the context or default ClassLoader."
|
||||
is="true"
|
||||
type="boolean"/>
|
||||
|
||||
<attribute name="validate"
|
||||
description="Should we validate client certificate chains when they are presented?"
|
||||
type="boolean"/>
|
||||
|
||||
|
||||
<operation name="start" description="Start" impact="ACTION" returnType="void" />
|
||||
<operation name="stop" description="Stop" impact="ACTION" returnType="void" />
|
||||
<operation name="init" description="Init" impact="ACTION" returnType="void" />
|
||||
<operation name="destroy" description="Destroy" impact="ACTION" returnType="void" />
|
||||
</mbean>
|
||||
|
||||
|
||||
<mbean name="JDBCRealm"
|
||||
description="Implementation of Realm that works with any JDBC supported database"
|
||||
domain="Catalina"
|
||||
group="Realm"
|
||||
type="org.apache.catalina.realm.JDBCRealm">
|
||||
|
||||
<attribute name="allRolesMode"
|
||||
description="The all roles mode."
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="className"
|
||||
description="Fully qualified class name of the managed object"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="connectionName"
|
||||
description="The connection username to use when trying to connect to the database"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="connectionPassword"
|
||||
description="The connection password to use when trying to connect to the database"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="connectionURL"
|
||||
description="The connection URL to use when trying to connect to the database"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="driverName"
|
||||
description="The JDBC driver to use"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="roleNameCol"
|
||||
description="The column in the user role table that names a role"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="realmPath"
|
||||
description="The realm path"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="stateName"
|
||||
description="The name of the LifecycleState that this component is currently in"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="userCredCol"
|
||||
description="The column in the user table that holds the user's credentials"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="userNameCol"
|
||||
description="The column in the user table that holds the user's username"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="userRoleTable"
|
||||
description="The table that holds the relation between user's and roles"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="userTable"
|
||||
description="The table that holds user data"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="validate"
|
||||
description="The 'validate certificate chains' flag."
|
||||
type="boolean"/>
|
||||
|
||||
|
||||
<operation name="start" description="Start" impact="ACTION" returnType="void" />
|
||||
<operation name="stop" description="Stop" impact="ACTION" returnType="void" />
|
||||
<operation name="init" description="Init" impact="ACTION" returnType="void" />
|
||||
<operation name="destroy" description="Destroy" impact="ACTION" returnType="void" />
|
||||
</mbean>
|
||||
|
||||
<mbean name="JNDIRealm"
|
||||
description="Implementation of Realm that works with a directory server accessed via the Java Naming and Directory Interface (JNDI) APIs"
|
||||
domain="Catalina"
|
||||
group="Realm"
|
||||
type="org.apache.catalina.realm.JNDIRealm">
|
||||
|
||||
<attribute name="adCompat"
|
||||
description=" The current settings for handling PartialResultExceptions"
|
||||
type="boolean"/>
|
||||
|
||||
<attribute name="allRolesMode"
|
||||
description="The all roles mode."
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="alternateURL"
|
||||
description="The Alternate URL"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="authentication"
|
||||
description="The type of authentication to use"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="className"
|
||||
description="Fully qualified class name of the managed object"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="commonRole"
|
||||
description="The common role"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="connectionName"
|
||||
description="The connection username for the server we will contact"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="connectionPassword"
|
||||
description="The connection password for the server we will contact"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="connectionTimeout"
|
||||
description="The connection timeout"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="connectionURL"
|
||||
description="The connection URL for the server we will contact"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="contextFactory"
|
||||
description="The JNDI context factory for this Realm"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="protocol"
|
||||
description="The protocol to be used"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="realmPath"
|
||||
description="The realm path"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="referrals"
|
||||
description="The current setting for handling JNDI referrals."
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="roleBase"
|
||||
description="The base element for role searches"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="roleName"
|
||||
description="The name of the attribute containing roles held elsewhere"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="roleNested"
|
||||
description="The 'The nested group search flag' flag"
|
||||
type="boolean"/>
|
||||
|
||||
<attribute name="roleSearch"
|
||||
description="The message format used to select roles for a user"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="roleSearchAsUser"
|
||||
description="Should the search for user roles be performed as the authenticating user?"
|
||||
is="true"
|
||||
type="boolean"/>
|
||||
|
||||
<attribute name="roleSubtree"
|
||||
description="Should we search the entire subtree for matching memberships?"
|
||||
type="boolean"/>
|
||||
|
||||
<attribute name="stateName"
|
||||
description="The name of the LifecycleState that this component is currently in"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="userBase"
|
||||
description="The base element for user searches"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="userPassword"
|
||||
description="The attribute name used to retrieve the user password"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="userPattern"
|
||||
description="The message format used to select a user"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="userRoleName"
|
||||
description="The name of the attribute in the user's entry containing roles for that user"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="userSearch"
|
||||
description="The message format used to search for a user"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="userSearchAsUser"
|
||||
description="Should the search for the user's DN be performed as the authenticating user?"
|
||||
is="true"
|
||||
type="boolean"/>
|
||||
|
||||
<attribute name="userSubtree"
|
||||
description="Should we search the entire subtree for matching users?"
|
||||
type="boolean"/>
|
||||
|
||||
<attribute name="validate"
|
||||
description="The 'validate certificate chains' flag."
|
||||
type="boolean"/>
|
||||
|
||||
|
||||
<operation name="start" description="Start" impact="ACTION" returnType="void" />
|
||||
<operation name="stop" description="Stop" impact="ACTION" returnType="void" />
|
||||
<operation name="init" description="Init" impact="ACTION" returnType="void" />
|
||||
<operation name="destroy" description="Destroy" impact="ACTION" returnType="void" />
|
||||
</mbean>
|
||||
|
||||
<mbean name="MemoryRealm"
|
||||
description="Simple implementation of Realm that reads an XML file to configure the valid users, passwords, and roles"
|
||||
domain="Catalina"
|
||||
group="Realm"
|
||||
type="org.apache.catalina.realm.MemoryRealm">
|
||||
|
||||
<attribute name="allRolesMode"
|
||||
description="The all roles mode."
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="className"
|
||||
description="Fully qualified class name of the managed object"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="pathname"
|
||||
description="The pathname of the XML file containing our database information"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="realmPath"
|
||||
description="The realm path"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="stateName"
|
||||
description="The name of the LifecycleState that this component is currently in"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="validate"
|
||||
description="The 'validate certificate chains' flag."
|
||||
type="boolean"/>
|
||||
|
||||
<operation name="start" description="Start" impact="ACTION" returnType="void" />
|
||||
<operation name="stop" description="Stop" impact="ACTION" returnType="void" />
|
||||
<operation name="init" description="Init" impact="ACTION" returnType="void" />
|
||||
<operation name="destroy" description="Destroy" impact="ACTION" returnType="void" />
|
||||
|
||||
</mbean>
|
||||
|
||||
<mbean name="UserDatabaseRealm"
|
||||
description="Realm connected to a UserDatabase as a global JNDI resource"
|
||||
domain="Catalina"
|
||||
group="Realm"
|
||||
type="org.apache.catalina.realm.UserDatabaseRealm">
|
||||
|
||||
<attribute name="allRolesMode"
|
||||
description="The all roles mode."
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="className"
|
||||
description="Fully qualified class name of the managed object"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="resourceName"
|
||||
description="The global JNDI name of the UserDatabase resource to use"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="realmPath"
|
||||
description="The realm path"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="stateName"
|
||||
description="The name of the LifecycleState that this component is currently in"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="validate"
|
||||
description="The 'validate certificate chains' flag."
|
||||
type="boolean"/>
|
||||
|
||||
<operation name="start" description="Start" impact="ACTION" returnType="void" />
|
||||
<operation name="stop" description="Stop" impact="ACTION" returnType="void" />
|
||||
<operation name="init" description="Init" impact="ACTION" returnType="void" />
|
||||
<operation name="destroy" description="Destroy" impact="ACTION" returnType="void" />
|
||||
|
||||
</mbean>
|
||||
|
||||
<mbean name="CombinedRealm"
|
||||
description="Realm implementation that can be used to chain multiple realms"
|
||||
domain="Catalina"
|
||||
group="Realm"
|
||||
type="org.apache.catalina.realm.CombinedRealm">
|
||||
|
||||
<attribute name="allRolesMode"
|
||||
description="The all roles mode."
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="className"
|
||||
description="Fully qualified class name of the managed object"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="realms"
|
||||
description="The set of realms that the combined realm is wrapping"
|
||||
type="[Ljavax.management.ObjectName;"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="realmPath"
|
||||
description="The realm path"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="stateName"
|
||||
description="The name of the LifecycleState that this component is currently in"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="validate"
|
||||
description="The 'validate certificate chains' flag."
|
||||
type="boolean"/>
|
||||
|
||||
<operation name="addRealm"
|
||||
description="Add a new Realm to the set of Realms wrapped by this realm"
|
||||
impact="ACTION"
|
||||
returnType="void">
|
||||
<parameter name="theRealm"
|
||||
description="New Realm to add"
|
||||
type="org.apache.catalina.Realm"/>
|
||||
</operation>
|
||||
|
||||
<operation name="start" description="Start" impact="ACTION" returnType="void" />
|
||||
<operation name="stop" description="Stop" impact="ACTION" returnType="void" />
|
||||
<operation name="init" description="Init" impact="ACTION" returnType="void" />
|
||||
<operation name="destroy" description="Destroy" impact="ACTION" returnType="void" />
|
||||
|
||||
</mbean>
|
||||
|
||||
<mbean name="LockOutRealm"
|
||||
description="Realm implementation that can be used to wrap existing realms to provide a user lock-out capability"
|
||||
domain="Catalina"
|
||||
group="Realm"
|
||||
type="org.apache.catalina.realm.LockOutRealm">
|
||||
|
||||
<attribute name="allRolesMode"
|
||||
description="The all roles mode."
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="cacheSize"
|
||||
description="Number of users that have failed authentication to keep in cache. Over time the cache will grow to this size and may not shrink. Defaults to 1000."
|
||||
type="int" />
|
||||
|
||||
<attribute name="cacheRemovalWarningTime"
|
||||
description="If a failed user is removed from the cache because the cache is too big before it has been in the cache for at least this period of time (in seconds) a warning message will be logged. Defaults to 3600 (1 hour)."
|
||||
type="int" />
|
||||
|
||||
<attribute name="className"
|
||||
description="Fully qualified class name of the managed object"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="failureCount"
|
||||
description="The number of times in a row a user has to fail authentication to be locked out. Defaults to 5."
|
||||
type="int" />
|
||||
|
||||
<attribute name="lockOutTime"
|
||||
description="The time (in seconds) a user is locked out for after too many authentication failures. Defaults to 300 (5 minutes)."
|
||||
type="int" />
|
||||
|
||||
<attribute name="realms"
|
||||
description="The set of realms that the lockout realm is wrapping"
|
||||
type="[Ljavax.management.ObjectName;"
|
||||
writeable="false"/>
|
||||
|
||||
<attribute name="realmPath"
|
||||
description="The realm path"
|
||||
type="java.lang.String"/>
|
||||
|
||||
<attribute name="validate"
|
||||
description="The 'validate certificate chains' flag."
|
||||
type="boolean"/>
|
||||
|
||||
<operation name="addRealm"
|
||||
description="Add a new Realm to the set of Realms wrapped by this realm"
|
||||
impact="ACTION"
|
||||
returnType="void">
|
||||
<parameter name="theRealm"
|
||||
description="New Realm to add"
|
||||
type="org.apache.catalina.Realm"/>
|
||||
</operation>
|
||||
|
||||
<operation name="isLocked"
|
||||
description="Determine if the specified user is locked"
|
||||
impact="ACTION"
|
||||
returnType="boolean">
|
||||
<parameter name="username"
|
||||
description="User to test for being locked"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
|
||||
<operation name="unlock"
|
||||
description="Unlock the specified user"
|
||||
impact="ACTION"
|
||||
returnType="void">
|
||||
<parameter name="username"
|
||||
description="User to unlock"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
|
||||
<operation name="start" description="Start" impact="ACTION" returnType="void" />
|
||||
<operation name="stop" description="Stop" impact="ACTION" returnType="void" />
|
||||
<operation name="init" description="Init" impact="ACTION" returnType="void" />
|
||||
<operation name="destroy" description="Destroy" impact="ACTION" returnType="void" />
|
||||
|
||||
</mbean>
|
||||
|
||||
</mbeans-descriptors>
|
||||
30
java/org/apache/catalina/realm/package.html
Normal file
30
java/org/apache/catalina/realm/package.html
Normal file
@@ -0,0 +1,30 @@
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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.
|
||||
-->
|
||||
<body>
|
||||
|
||||
<p>This package contains <code>Realm</code> implementations for the
|
||||
various supported realm technologies for authenticating users and
|
||||
identifying their associated roles. The <code>Realm</code> that is
|
||||
associated with a web application's <code>Context</code> (or a hierarchically
|
||||
superior Container) is used to resolve authentication and role presence
|
||||
questions when a web application uses container managed security as described
|
||||
in the Servlet API Specification.</p>
|
||||
|
||||
<p>The implementations share a common base class that supports basic
|
||||
functionality for all of the standard <code>Realm</code> implementations.</p>
|
||||
|
||||
</body>
|
||||
Reference in New Issue
Block a user