/* * 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;
/** * 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. * * @author Craig R. McClanahan
*/ publicabstractclass RealmBase extends LifecycleMBeanBase implements Realm {
/** * The character used for delimiting user attribute names. * <p> * Applies to some of the Realm implementations only.
*/ protectedstaticfinal String USER_ATTRIBUTES_DELIMITER = ",";
/** * The character used as wildcard in user attribute lists. Using it means <i>query all available user * attributes</i>. * <p> * Applies to some of the Realm implementations only.
*/ protectedstaticfinal String USER_ATTRIBUTES_WILDCARD = "*";
privatestaticfinal List<Class<? extends DigestCredentialHandlerBase>> credentialHandlerClasses = new ArrayList<>();
static { // Order is important since it determines the search order for a // matching handler if only an algorithm is specified when calling // main()
credentialHandlerClasses.add(MessageDigestCredentialHandler.class);
credentialHandlerClasses.add(SecretKeyCredentialHandler.class);
}
/** * The string manager for this package.
*/ protectedstaticfinal StringManager sm = StringManager.getManager(RealmBase.class);
/** * The property change support for this component.
*/ protectedfinal PropertyChangeSupport support = new PropertyChangeSupport(this);
/** * Should we validate client certificate chains when they are presented?
*/ protectedboolean validate = true;
/** * The name of the class to use for retrieving user names from X509 certificates.
*/ protected String x509UsernameRetrieverClassName;
/** * The object that will extract user names from X509 client certificates.
*/ protected X509UsernameRetriever x509UsernameRetriever;
/** * The all role mode.
*/ protected AllRolesMode allRolesMode = AllRolesMode.STRICT_MODE;
/** * When processing users authenticated via the GSS-API, should any "@..." be stripped from the end of the * user name?
*/ protectedboolean stripRealmForGss = true;
/** * The comma separated names of user attributes to additionally query from the realm. These will be provided to the * user through the created Principal's <i>attributes</i> map. Support for this feature is optional.
*/ protected String userAttributes = null;
/** * The list of user attributes to additionally query from the realm. These will be provided to the user through the * created Principal's <i>attributes</i> map. Support for this feature is optional.
*/ protected List<String> userAttributesList = null;
/** * @return The HTTP status code used when the container needs to issue an HTTP redirect to meet the requirements of * a configured transport guarantee.
*/ publicint getTransportGuaranteeRedirectStatus() { return transportGuaranteeRedirectStatus;
}
/** * Set the HTTP status code used when the container needs to issue an HTTP redirect to meet the requirements of a * configured transport guarantee. * * @param transportGuaranteeRedirectStatus The status to use. This value is not validated
*/ publicvoid setTransportGuaranteeRedirectStatus(int transportGuaranteeRedirectStatus) { this.transportGuaranteeRedirectStatus = transportGuaranteeRedirectStatus;
}
@Override public CredentialHandler getCredentialHandler() { return credentialHandler;
}
/** * Return the all roles mode. * * @return A string representation of the current all roles mode
*/ public String getAllRolesMode() { return allRolesMode.toString();
}
/** * Set the all roles mode. * * @param allRolesMode A string representation of the new all roles mode
*/ publicvoid setAllRolesMode(String allRolesMode) { this.allRolesMode = AllRolesMode.toMode(allRolesMode);
}
/** * Return the "validate certificate chains" flag. * * @return The value of the validate certificate chains flag
*/ publicboolean getValidate() { return validate;
}
/** * Set the "validate certificate chains" flag. * * @param validate The new validate certificate chains flag
*/ publicvoid setValidate(boolean validate) {
this.validate = validate;
}
/** * Gets the name of the class that will be used to extract user names from X509 client certificates. * * @return The name of the class that will be used to extract user names from X509 client certificates.
*/ public String getX509UsernameRetrieverClassName() { return x509UsernameRetrieverClassName;
}
/** * Sets the name of the class that will be used to extract user names from X509 client certificates. The class must * implement X509UsernameRetriever. * * @param className The name of the class that will be used to extract user names from X509 client certificates. * * @see X509UsernameRetriever
*/ publicvoid setX509UsernameRetrieverClassName(String className) { this.x509UsernameRetrieverClassName = className;
}
/** * @return the comma separated names of user attributes to additionally query from realm
*/ public String getUserAttributes() { return userAttributes;
}
/** * Set the comma separated names of user attributes to additionally query from the realm. These will be provided to * the user through the created Principal's <i>attributes</i> map. In this map, each field value is bound to the * field's name, that is, the name of the field serves as the key of the mapping. * <p> * If set to the wildcard character, or, if the wildcard character is part of the comma separated list, all * available attributes - except the <i>password</i> attribute (as specified by <code>userCredCol</code>) - are * queried. The wildcard character is defined by constant {@link RealmBase#USER_ATTRIBUTES_WILDCARD}. It defaults to * the asterisk (*) character. * * @param userAttributes the comma separated names of user attributes
*/ publicvoid setUserAttributes(String userAttributes) { this.userAttributes = userAttributes;
}
// --------------------------------------------------------- Public Methods
@Override public Principal authenticate(String username) {
if (username == null) { returnnull;
}
if (containerLog.isTraceEnabled()) {
containerLog.trace(sm.getString("realmBase.authenticateSuccess", username));
}
return getPrincipal(username);
}
@Override public Principal authenticate(String username, String credentials) { // No user or no credentials // Can't possibly authenticate, don't bother doing anything. if (username == null || credentials == null) { if (containerLog.isTraceEnabled()) {
containerLog.trace(sm.getString("realmBase.authenticateFailure", username));
} returnnull;
}
// Look up the user's credentials
String serverCredentials = getPassword(username);
if (serverCredentials == null) { // User was not found // 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("realmBase.authenticateFailure", username));
} returnnull;
}
@Override public Principal authenticate(GSSName gssName, GSSCredential gssCredential) { if (gssName == null) { returnnull;
}
return getPrincipal(gssName, gssCredential);
}
/** * {@inheritDoc} * <p> * The default implementation is NO-OP.
*/
@Override publicvoid backgroundProcess() { // NOOP in base class
}
@Override public SecurityConstraint[] findSecurityConstraints(Request request, Context context) {
ArrayList<SecurityConstraint> results = null; // Are there any defined security constraints?
SecurityConstraint constraints[] = context.findConstraints(); if (constraints == null || constraints.length == 0) { if (log.isDebugEnabled()) {
log.debug(" No applicable constraints defined");
} returnnull;
}
// Check each defined security constraint
String uri = request.getRequestPathMB().toString(); // Bug47080 - in rare cases this may be null or "" // Mapper treats as '/' do the same to prevent NPE if (uri == null || uri.length() == 0) {
uri = "/";
}
String method = request.getMethod(); int i; boolean found = false; for (i = 0; i < constraints.length; i++) {
SecurityCollection[] collections = constraints[i].findCollections();
// If collection is null, continue to avoid an NPE // See Bugzilla 30624 if (collections == null) { continue;
}
if (log.isDebugEnabled()) {
log.debug(" Checking constraint '" + constraints[i] + "' against " + method + " " + uri + " --> " +
constraints[i].included(uri, method));
}
for (SecurityCollection securityCollection : collections) {
String[] patterns = securityCollection.findPatterns();
// If patterns is null, continue to avoid an NPE // See Bugzilla 30624 if (patterns == null) { continue;
}
for (String pattern : patterns) { // Exact match including special case for the context root. if (uri.equals(pattern) || pattern.length() == 0 && uri.equals("/")) {
found = true; if (securityCollection.findMethod(method)) { if (results == null) {
results = new ArrayList<>();
}
results.add(constraints[i]);
}
}
}
}
}
if (found) { return resultsToArray(results);
}
int longest = -1;
for (i = 0; i < constraints.length; i++) {
SecurityCollection[] collection = constraints[i].findCollections();
// If collection is null, continue to avoid an NPE // See Bugzilla 30624 if (collection == null) { continue;
}
if (log.isDebugEnabled()) {
log.debug(" Checking constraint '" + constraints[i] + "' against " + method + " " + uri + " --> " +
constraints[i].included(uri, method));
}
for (SecurityCollection securityCollection : collection) {
String[] patterns = securityCollection.findPatterns();
// If patterns is null, continue to avoid an NPE // See Bugzilla 30624 if (patterns == null) { continue;
}
boolean matched = false; int length = -1; for (String pattern : patterns) { if (pattern.startsWith("/") && pattern.endsWith("/*") && pattern.length() >= longest) {
if (pattern.length() == 2) {
matched = true;
length = pattern.length();
} elseif (pattern.regionMatches(0, uri, 0, pattern.length() - 1) ||
(pattern.length() - 2 == uri.length() &&
pattern.regionMatches(0, uri, 0, pattern.length() - 2))) {
matched = true;
length = pattern.length();
}
}
} if (matched) { if (length > longest) {
found = false; if (results != null) {
results.clear();
}
longest = length;
} if (securityCollection.findMethod(method)) {
found = true; if (results == null) {
results = new ArrayList<>();
}
results.add(constraints[i]);
}
}
}
}
if (found) { return resultsToArray(results);
}
for (i = 0; i < constraints.length; i++) {
SecurityCollection[] collection = constraints[i].findCollections();
// If collection is null, continue to avoid an NPE // See Bugzilla 30624 if (collection == null) { continue;
}
if (log.isDebugEnabled()) {
log.debug(" Checking constraint '" + constraints[i] + "' against " + method + " " + uri + " --> " +
constraints[i].included(uri, method));
}
// If patterns is null, continue to avoid an NPE // See Bugzilla 30624 if (patterns == null) { continue;
}
for (int k = 0; k < patterns.length && !matched; k++) {
String pattern = patterns[k]; if (pattern.startsWith("*.")) { int slash = uri.lastIndexOf('/'); int dot = uri.lastIndexOf('.'); if (slash >= 0 && dot > slash && dot != uri.length() - 1 &&
uri.length() - dot == pattern.length() - 1) { if (pattern.regionMatches(1, uri, dot, uri.length() - dot)) {
matched = true;
pos = j;
}
}
}
}
} if (matched) {
found = true; if (collection[pos].findMethod(method)) { if (results == null) {
results = new ArrayList<>();
}
results.add(constraints[i]);
}
}
}
if (found) { return resultsToArray(results);
}
for (i = 0; i < constraints.length; i++) {
SecurityCollection[] collection = constraints[i].findCollections();
// If collection is null, continue to avoid an NPE // See Bugzilla 30624 if (collection == null) { continue;
}
if (log.isDebugEnabled()) {
log.debug(" Checking constraint '" + constraints[i] + "' against " + method + " " + uri + " --> " +
constraints[i].included(uri, method));
}
for (SecurityCollection securityCollection : collection) {
String[] patterns = securityCollection.findPatterns();
// If patterns is null, continue to avoid an NPE // See Bugzilla 30624 if (patterns == null) { continue;
}
boolean matched = false; for (String pattern : patterns) { if (pattern.equals("/")) {
matched = true; break;
}
} if (matched) { if (results == null) {
results = new ArrayList<>();
}
results.add(constraints[i]);
}
}
}
if (results == null) { // No applicable security constraint was found if (log.isDebugEnabled()) {
log.debug(" No applicable constraint located");
}
} return resultsToArray(results);
}
/** * Convert an ArrayList to a SecurityConstraint [].
*/ private SecurityConstraint[] resultsToArray(ArrayList<SecurityConstraint> results) { if (results == null || results.size() == 0) { returnnull;
} return results.toArray(new SecurityConstraint[0]);
}
// Which user principal have we already authenticated?
Principal principal = request.getPrincipal(); boolean status = false; boolean denyfromall = false; for (SecurityConstraint constraint : constraints) {
String roles[]; if (constraint.getAllRoles()) { // * means all roles defined in web.xml
roles = request.getContext().findSecurityRoles();
} else {
roles = constraint.findAuthRoles();
}
if (roles == null) {
roles = new String[0];
}
if (log.isDebugEnabled()) {
log.debug(" Checking roles " + principal);
}
if (constraint.getAuthenticatedUsers() && principal != null) { if (log.isDebugEnabled()) {
log.debug("Passing all authenticated users");
}
status = true;
} elseif (roles.length == 0 && !constraint.getAllRoles() && !constraint.getAuthenticatedUsers()) { if (constraint.getAuthConstraint()) { if (log.isDebugEnabled()) {
log.debug("No roles");
}
status = false; // No listed roles means no access at all
denyfromall = true; break;
}
if (log.isDebugEnabled()) {
log.debug("Passing all access");
}
status = true;
} elseif (principal == null) { if (log.isDebugEnabled()) {
log.debug(" No user authenticated, cannot grant access");
}
} else { for (String role : roles) { if (hasRole(request.getWrapper(), principal, role)) {
status = true; if (log.isDebugEnabled()) {
log.debug("Role found: " + role);
}
} elseif (log.isDebugEnabled()) {
log.debug("No role found: " + role);
}
}
}
}
if (!denyfromall && allRolesMode != AllRolesMode.STRICT_MODE && !status && principal != null) { if (log.isDebugEnabled()) {
log.debug("Checking for all roles mode: " + allRolesMode);
} // Check for an all roles(role-name="*") for (SecurityConstraint constraint : constraints) {
String roles[]; // If the all roles mode exists, sets if (constraint.getAllRoles()) { if (allRolesMode == AllRolesMode.AUTH_ONLY_MODE) { if (log.isDebugEnabled()) {
log.debug("Granting access for role-name=*, auth-only");
}
status = true; break;
}
// For AllRolesMode.STRICT_AUTH_ONLY_MODE there must be zero roles
roles = request.getContext().findSecurityRoles(); if (roles == null) {
roles = new String[0];
} if (roles.length == 0 && allRolesMode == AllRolesMode.STRICT_AUTH_ONLY_MODE) { if (log.isDebugEnabled()) {
log.debug("Granting access for role-name=*, strict auth-only");
}
status = true; break;
}
}
}
}
// Return a "Forbidden" message denying access to this resource if (!status) {
response.sendError(HttpServletResponse.SC_FORBIDDEN, sm.getString("realmBase.forbidden"));
} return status;
}
/** * {@inheritDoc} * <p> * This method or {@link #hasRoleInternal(Principal, String)} can be overridden by Realm implementations, but the * default is adequate when an instance of <code>GenericPrincipal</code> is used to represent authenticated * Principals from this Realm.
*/
@Override publicboolean hasRole(Wrapper wrapper, Principal principal, String role) { // Check for a role alias if (wrapper != null) {
String realRole = wrapper.findSecurityReference(role); if (realRole != null) {
role = realRole;
}
}
// Should be overridden in JAASRealm - to avoid pretty inefficient conversions if (principal == null || role == null) { returnfalse;
}
boolean result = hasRoleInternal(principal, role);
if (log.isDebugEnabled()) {
String name = principal.getName(); if (result) {
log.debug(sm.getString("realmBase.hasRoleSuccess", name, role));
} else {
log.debug(sm.getString("realmBase.hasRoleFailure", name, role));
}
}
return result;
}
/** * Parse the specified delimiter separated attribute names and return a list of that names or <code>null</code>, if * no attributes have been specified. * <p> * If a wildcard character is found, return a list consisting of a single wildcard character only. * * @param userAttributes comma separated names of attributes to parse * * @return a list containing the parsed attribute names or <code>null</code>, if no attributes have been specified
*/ protected List<String> parseUserAttributes(String userAttributes) { if (userAttributes == null) { returnnull;
}
List<String> attrs = new ArrayList<>(); for (String name : userAttributes.split(USER_ATTRIBUTES_DELIMITER)) {
name = name.trim(); if (name.length() == 0) { continue;
} if (name.equals(USER_ATTRIBUTES_WILDCARD)) { return Collections.singletonList(USER_ATTRIBUTES_WILDCARD);
} if (attrs.contains(name)) { // skip duplicates continue;
}
attrs.add(name);
} return attrs.size() > 0 ? attrs : null;
}
/** * Check if the specified Principal has the specified security role, within the context of this Realm. This method * or {@link #hasRoleInternal(Principal, String)} can be overridden by Realm implementations, but the default is * adequate when an instance of <code>GenericPrincipal</code> is used to represent authenticated Principals from * this Realm. * * @param principal Principal for whom the role is to be checked * @param role Security role to be checked * * @return <code>true</code> if the specified Principal has the specified security role, within the context of this * Realm; otherwise return <code>false</code>.
*/ protectedboolean hasRoleInternal(Principal principal, String role) { // Should be overridden in JAASRealm - to avoid pretty inefficient conversions if (!(principal instanceof GenericPrincipal)) { returnfalse;
}
GenericPrincipal gp = (GenericPrincipal) principal; return gp.hasRole(role);
}
// Is there a relevant user data constraint? if (constraints == null || constraints.length == 0) { if (log.isDebugEnabled()) {
log.debug(" No applicable security constraint defined");
} returntrue;
} for (SecurityConstraint constraint : constraints) {
String userConstraint = constraint.getUserConstraint(); if (userConstraint == null) { if (log.isDebugEnabled()) {
log.debug(" No applicable user data constraint defined");
} returntrue;
} if (userConstraint.equals(TransportGuarantee.NONE.name())) { if (log.isDebugEnabled()) {
log.debug(" User data constraint has no restrictions");
} returntrue;
}
} // Validate the request against the user data constraint if (request.getRequest().isSecure()) { if (log.isDebugEnabled()) {
log.debug(" User data constraint already satisfied");
} returntrue;
} // Initialize variables we need to determine the appropriate action int redirectPort = request.getConnector().getRedirectPortWithOffset();
// Is redirecting disabled? if (redirectPort <= 0) { if (log.isDebugEnabled()) {
log.debug(" SSL redirect is disabled");
}
response.sendError(HttpServletResponse.SC_FORBIDDEN, request.getRequestURI()); returnfalse;
}
// Redirect to the corresponding SSL port
StringBuilder file = new StringBuilder();
String protocol = "https";
String host = request.getServerName(); // Protocol
file.append(protocol).append("://").append(host); // Host with port if (redirectPort != 443) {
file.append(':').append(redirectPort);
} // URI
file.append(request.getRequestURI());
String requestedSessionId = request.getRequestedSessionId(); if ((requestedSessionId != null) && request.isRequestedSessionIdFromURL()) {
file.append(';');
file.append(SessionConfig.getSessionUriParamName(request.getContext()));
file.append('=');
file.append(requestedSessionId);
}
String queryString = request.getQueryString(); if (queryString != null) {
file.append('?');
file.append(queryString);
} if (log.isDebugEnabled()) {
log.debug(" Redirecting to " + file.toString());
}
response.sendRedirect(file.toString(), transportGuaranteeRedirectStatus); returnfalse;
/** * 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 protectedvoid startInternal() throws LifecycleException { if (credentialHandler == null) {
credentialHandler = new MessageDigestCredentialHandler();
} if (userAttributes != null) {
userAttributesList = parseUserAttributes(userAttributes);
}
setState(LifecycleState.STARTING);
}
/** * 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 protectedvoid stopInternal() throws LifecycleException {
setState(LifecycleState.STOPPING);
}
@Override public String toString() { return ToStringUtil.toString(this);
}
/** * Return the digest associated with given principal's user name. * * @param username The user name * @param realmName The realm name * * @return the digest for the specified user * * @deprecated Unused. Use {@link #getDigest(String, String, String)}. Will be removed in Tomcat 11.
*/
@Deprecated protected String getDigest(String username, String realmName) { return getDigest(username, realmName, "MD5");
}
/** * Return the digest associated with given principal's user name. * * @param username The user name * @param realmName The realm name * @param algorithm The name of the message digest algorithm to use * * @return the digest for the specified user
*/ protected String getDigest(String username, String realmName, String algorithm) { if (hasMessageDigest(algorithm)) { // Use pre-generated digest return getPassword(username);
}
/** * Get the password for the specified user. * * @param username The user name * * @return the password associated with the given principal's user name.
*/ protectedabstract String getPassword(String username);
/** * Get the principal associated with the specified certificate. * * @param usercert The user certificate * * @return the Principal associated with the given certificate.
*/ protected Principal getPrincipal(X509Certificate usercert) {
String username = x509UsernameRetriever.getUsername(usercert);
if (log.isDebugEnabled()) {
log.debug(sm.getString("realmBase.gotX509Username", username));
}
return getPrincipal(username);
}
/** * Get the principal associated with the specified user. * * @param username The user name * * @return the Principal associated with the given user name.
*/ protectedabstract Principal getPrincipal(String username);
/** * Get the principal associated with the specified {@link GSSName}. * * @param gssName The GSS name * @param gssCredential the GSS credential of the principal * * @return the principal associated with the given user name.
*/ protected Principal getPrincipal(GSSName gssName, GSSCredential gssCredential) {
String name = gssName.toString();
if (isStripRealmForGss()) { int i = name.indexOf('@'); if (i > 0) { // Zero so we don't leave a zero length name
name = name.substring(0, i);
}
}
Principal p = getPrincipal(name);
if (p instanceof GenericPrincipal) {
((GenericPrincipal) p).setGssCredential(gssCredential);
}
return p;
}
/** * Return the Server object that is the ultimate parent for the container with which this Realm is associated. If * the server cannot be found (eg because the container hierarchy is not complete), <code>null</code> is returned. * * @return the Server associated with the realm
*/ protected Server getServer() {
Container c = container; if (c instanceof Context) {
c = c.getParent();
} if (c instanceof Host) {
c = c.getParent();
} if (c instanceof Engine) {
Service s = ((Engine) c).getService(); if (s != null) { return s.getServer();
}
} returnnull;
}
/** * Generate a stored credential string for the given password and associated parameters. * <p> * The following parameters are supported: * </p> * <ul> * <li><b>-a</b> - The algorithm to use to generate the stored credential. If not specified a default of SHA-512 * will be used.</li> * <li><b>-e</b> - The encoding to use for any byte to/from character conversion that may be necessary. If not * specified, the system encoding ({@link Charset#defaultCharset()}) will be used.</li> * <li><b>-i</b> - The number of iterations to use when generating the stored credential. If not specified, the * default for the CredentialHandler will be used.</li> * <li><b>-s</b> - The length (in bytes) of salt to generate and store as part of the credential. If not specified, * the default for the CredentialHandler will be used.</li> * <li><b>-k</b> - The length (in bits) of the key(s), if any, created while generating the credential. If not * specified, the default for the CredentialHandler will be used.</li> * <li><b>-h</b> - The fully qualified class name of the CredentialHandler to use. If not specified, the built-in * handlers will be tested in turn and the first one to accept the specified algorithm will be used.</li> * </ul> * <p> * This generation process currently supports the following CredentialHandlers, the correct one being selected based * on the algorithm specified: * </p> * <ul> * <li>{@link MessageDigestCredentialHandler}</li> * <li>{@link SecretKeyCredentialHandler}</li> * </ul> * * @param args The parameters passed on the command line
*/ publicstaticvoid main(String args[]) {
// Use negative values since null is not an option to indicate 'not set' int saltLength = -1; int iterations = -1; int keyLength = -1; // Default
String encoding = Charset.defaultCharset().name(); // Default values for these depend on whether either of them are set on // the command line
String algorithm = null;
String handlerClassName = null;
// Determine defaults for -a and -h. The rules are more complex to // express than the implementation: // - if neither -a nor -h is set, use SHA-512 and // MessageDigestCredentialHandler // - if only -a is set the built-in handlers will be searched in order // (MessageDigestCredentialHandler, SecretKeyCredentialHandler) and // the first handler that supports the algorithm will be used // - if only -h is set no default will be used for -a. The handler may // or may nor support -a and may or may not supply a sensible default if (algorithm == null && handlerClassName == null) {
algorithm = "SHA-512";
}
privatefinal String name; /** * Use the strict servlet spec interpretation which requires that the user have one of the * web-app/security-role/role-name
*/ publicstaticfinal AllRolesMode STRICT_MODE = new AllRolesMode("strict"); /** Allow any authenticated user */ publicstaticfinal AllRolesMode AUTH_ONLY_MODE = new AllRolesMode("authOnly"); /** * Allow any authenticated user only if there are no web-app/security-roles
*/ publicstaticfinal AllRolesMode STRICT_AUTH_ONLY_MODE = new AllRolesMode("strictAuthOnly");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.