/*
* 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.jackrabbit.core.security.authentication;
import org.apache.jackrabbit.core.config.LoginModuleConfig;
import org.apache.jackrabbit.core.security.principal.PrincipalProviderRegistry;
import javax.jcr.Credentials;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
* <code>AuthContextProvider</code> defines how the current request for login is
* handled. By default the {@link org.apache.jackrabbit.core.config.RepositoryConfig
* local repository configuration} takes precedence over JAAS configuration.
* If no local configuration is present a JAAS configuration must be provided
* otherwise {@link #getAuthContext} fails with <code>RepositoryException</code>.
*/
public class AuthContextProvider {
private boolean initialized;
/**
* configuration state -> if a JAAS Configuration exists for this application
*/
private boolean isJAAS;
/**
* Configuration of the optional local LoginModule
*/
private final LoginModuleConfig config;
/**
* Application Name for the LoginConfig entry
*/
private final String appName;
/**
* @param appName LoginConfig application name used for this instance
* @param config optional LoginModule-configuration to use without JAAS
*/
public AuthContextProvider(String appName, LoginModuleConfig config) {
this.appName = appName;
this.config = config;
}
/**
*
* @param credentials
* @param subject
* @param session
* @param principalProviderRegistry
* @param adminId
* @param anonymousId
* @return context of for authentication and log-out
* @throws RepositoryException in case neither an <code>JAASContext</code>
* nor a <code>LocalContext</code> can be successfully created.
*/
public AuthContext getAuthContext(Credentials credentials,
Subject subject,
Session session,
PrincipalProviderRegistry principalProviderRegistry,
String adminId,
String anonymousId)
throws RepositoryException {
CallbackHandler cbHandler = new CallbackHandlerImpl(credentials, session, principalProviderRegistry, adminId, anonymousId);
if (isLocal()) {
return new LocalAuthContext(config, cbHandler, subject);
} else if (isJAAS()) {
return new JAASAuthContext(appName, cbHandler, subject);
} else {
throw new RepositoryException("No Login-Configuration");
}
}
/**
* @return true if a application entry is available in a JAAS- {@link Configuration}
*/
public boolean isJAAS() {
if (!isLocal() && !initialized) {
AppConfigurationEntry[] entries = getJAASConfig();
isJAAS = entries != null && entries.length > 0;
initialized = true;
}
return isJAAS;
}
/**
* @return true if a login-module is configured.
*/
public boolean isLocal() {
return config != null;
}
/**
* @return options configured for the LoginModules to use.
*/
public Properties[] getModuleConfig() {
Properties[] props = new Properties[0];
if (isLocal()) {
props = new Properties[] {config.getParameters()};
} else {
AppConfigurationEntry[] entries = getJAASConfig();
if (entries != null) {
List<Properties> tmp = new ArrayList<Properties>(entries.length);
for (AppConfigurationEntry entry : entries) {
Map opt = entry.getOptions();
if (opt != null) {
Properties prop = new Properties();
prop.putAll(opt);
tmp.add(prop);
}
}
props = tmp.toArray(new Properties[tmp.size()]);
}
}
return props;
}
/**
* @return all JAAS-Login Modules for this application or null if none
*/
private AppConfigurationEntry[] getJAASConfig() {
// check if jaas-loginModule or fallback is configured
Configuration logins = null;
try {
logins = Configuration.getConfiguration();
} catch (Exception e) {
// means no JAAS configuration file OR no permission to read it
}
if (logins != null) {
try {
return logins.getAppConfigurationEntry(appName);
} catch (Exception e) {
// WLP 9.2.0 throws IllegalArgumentException for unknown appName
}
}
return null;
}
}