blob: e0702836ad652d19a645b022df655829d9d0c8f6 [file] [log] [blame]
// Copyright 2009 Google Inc.
//
// Licensed 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 com.google.enterprise.secmgr.config;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Objects;
import com.google.common.base.Pair;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.enterprise.secmgr.json.ProxyTypeAdapter;
import com.google.enterprise.secmgr.json.TypeAdapters;
import com.google.enterprise.secmgr.json.TypeProxy;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
/**
* A class that holds a complete security manager configuration.
*/
@ThreadSafe
public final class SecurityManagerConfig {
static final int CURRENT_VERSION = 5;
private final int version;
@GuardedBy("this") private ImmutableList<CredentialGroup> credentialGroups;
@GuardedBy("this") private ImmutableList<AuthnMechanism> mechanisms;
@GuardedBy("this") private ConfigParams params;
@GuardedBy("this") private FlexAuthorizer flexAuthorizer;
private SecurityManagerConfig(int version, ImmutableList<CredentialGroup> credentialGroups,
ConfigParams params, FlexAuthorizer flexAuthorizer) {
this.version = version;
setCredentialGroupsInternal(credentialGroups);
this.params = params;
this.flexAuthorizer = flexAuthorizer;
}
/**
* Set a configuration's credential groups. The security manager uses this
* only for testing.
*
* @param credentialGroups The new credential groups.
* @throws IllegalArgumentException if there's a problem with the argument.
*/
public void setCredentialGroupsInternal(ImmutableList<CredentialGroup> credentialGroups) {
ImmutableList.Builder<AuthnMechanism> mechanismsBuilder = ImmutableList.builder();
for (CredentialGroup credentialGroup : credentialGroups) {
mechanismsBuilder.addAll(credentialGroup.getMechanisms());
}
ImmutableList<AuthnMechanism> mechanisms = mechanismsBuilder.build();
synchronized (this) {
this.credentialGroups = credentialGroups;
this.mechanisms = mechanisms;
}
}
/**
* Make a security manager configuration.
*
* @param credentialGroups The configuration's credential groups.
* @param params The configuration's parameters.
* @param flexAuthorizer The flex authorization configs
* @return A security manager configuration.
*/
public static SecurityManagerConfig make(Iterable<CredentialGroup> credentialGroups,
ConfigParams params, FlexAuthorizer flexAuthorizer) {
Preconditions.checkArgument(params != null);
Preconditions.checkArgument(flexAuthorizer != null);
return new SecurityManagerConfig(CURRENT_VERSION, checkCredentialGroups(credentialGroups),
params, flexAuthorizer);
}
@VisibleForTesting
public static SecurityManagerConfig make(Iterable<CredentialGroup> credentialGroups) {
return new SecurityManagerConfig(CURRENT_VERSION, checkCredentialGroups(credentialGroups),
ConfigParams.makeDefault(),
FlexAuthorizerImpl.makeDefault());
}
static SecurityManagerConfig makeInternal(int version, Iterable<CredentialGroup> credentialGroups,
ConfigParams params, FlexAuthorizer flexAuthorizer) {
Preconditions.checkArgument(version > 0 && version <= CURRENT_VERSION);
return new SecurityManagerConfig(
version,
checkCredentialGroups(credentialGroups),
(params != null) ? params : ConfigParams.makeDefault(),
(flexAuthorizer != null) ? flexAuthorizer : FlexAuthorizerImpl.makeDefault());
}
private static ImmutableList<CredentialGroup> checkCredentialGroups(
Iterable<CredentialGroup> credentialGroups) {
Preconditions.checkNotNull(credentialGroups);
ImmutableList<CredentialGroup> copy = ImmutableList.copyOf(credentialGroups);
Collection<String> names = Lists.newArrayList();
for (CredentialGroup group : copy) {
checkConfigName(group.getName(), names);
for (AuthnMechanism mech : group.getMechanisms()) {
checkConfigName(mech.getName(), names);
}
}
return copy;
}
private static void checkConfigName(String name, Collection<String> names) {
if (name != null) {
name = name.toLowerCase(Locale.US);
Preconditions.checkArgument(!names.contains(name),
"Configuration name appears more than once: %s", name);
names.add(name);
}
}
/**
* @return A default security manager configuration.
*/
public static SecurityManagerConfig makeDefault() {
return SecurityManagerConfig.make(
makeDefaultCredentialGroups(),
ConfigParams.makeDefault(),
FlexAuthorizerImpl.makeDefault());
}
public static ImmutableList<CredentialGroup> makeDefaultCredentialGroups() {
return ImmutableList.of(CredentialGroup.builder().build());
}
/**
* @return The configuration's version.
*/
int getVersion() {
return version;
}
/**
* Gets the credential groups contained in this configuration.
*
* @return The credential groups as an immutable list. The order is the same
* as was given when this configuration was created.
*/
public synchronized ImmutableList<CredentialGroup> getCredentialGroups() {
return credentialGroups;
}
/**
* Set a configuration's credential groups. The security manager uses this
* only for testing.
*
* @param credentialGroups The new credential groups.
* @throws IllegalArgumentException if there's a problem with the argument.
*/
public void setCredentialGroups(Iterable<CredentialGroup> credentialGroups) {
setCredentialGroupsInternal(checkCredentialGroups(credentialGroups));
ConfigSingleton.setChanged();
}
/**
* Gets the authentication mechanisms contained in this configuration.
*
* @return The mechanisms as an immutable list. The order is the same as was
* given when this configuration was created.
*/
public synchronized ImmutableList<AuthnMechanism> getMechanisms() {
return mechanisms;
}
/**
* Gets the credential group for a given mechanism.
*
* @param mechanism The mechanism to get the credential group for.
* @return The credential group for the given mechanism.
* @throws IllegalArgumentException if the mechanism isn't contained in this
* configuration.
*/
public CredentialGroup getCredentialGroup(AuthnMechanism mechanism) {
for (CredentialGroup credentialGroup : getCredentialGroups()) {
if (credentialGroup.getMechanisms().contains(mechanism)) {
return credentialGroup;
}
}
throw new IllegalArgumentException("Unknown mechanism: " + mechanism);
}
/**
* Gets the credential group with a given name.
*
* @param name The credential-group name to search for.
* @return The credential group with that name.
* @throws IllegalArgumentException if there's no credential group with that name.
*/
public CredentialGroup getCredentialGroup(String name) {
Preconditions.checkNotNull(name);
for (CredentialGroup credentialGroup : getCredentialGroups()) {
if (name.equalsIgnoreCase(credentialGroup.getName())) {
return credentialGroup;
}
}
throw new IllegalArgumentException("No credential group with this name: " + name);
}
/**
* Gets an authority predicate for a given credential group.
*
* @param credentialGroup A credential group to get the predicate for.
* @return The authority predicate for the credential group.
* @throws IllegalArgumentException if the credential group isn't contained in
* this configuration.
*/
public Predicate<AuthnAuthority> getAuthorityPredicate(CredentialGroup credentialGroup) {
ImmutableSet.Builder<AuthnAuthority> builder = ImmutableSet.builder();
builder.add(credentialGroup.getAuthority());
for (AuthnMechanism mechanism : credentialGroup.getMechanisms()) {
builder.add(mechanism.getAuthority());
}
return Predicates.in(builder.build());
}
public synchronized FlexAuthorizer getFlexAuthorizer() {
return flexAuthorizer;
}
/**
* Sets this configurations's flex authorizer. The security manager uses this
* only for testing.
*/
public void setFlexAuthorizer(FlexAuthorizer flexAuthorizer) {
synchronized (this) {
this.flexAuthorizer = flexAuthorizer;
}
ConfigSingleton.setChanged();
}
/**
* @return The configuration parameters.
*/
public synchronized ConfigParams getParams() {
return params;
}
/**
* Gets a list of credential group name and mechanism name pair for the mechanism.
*
* @param mechanismType the authentication mechanism type
* @return a list of credential group name and mechanism name pair for the mechanism.
*/
public <T extends AuthnMechanism> List<Pair<String, String>> getMechanism(
final Class<T> mechanismType) {
List<Pair<String, String>> mechanisms = Lists.newArrayList();
for (CredentialGroup group : getCredentialGroups()) {
for (AuthnMechanism mech : group.getMechanisms()) {
if (mechanismType.isInstance(mech)) {
mechanisms.add(Pair.of(group.getName(), mech.getName()));
}
}
}
return mechanisms;
}
/**
* Checks if the mechanism is configured.
*
* @param mechanismType the authentication mechanism type
* @return true if the mechanism is already configured.
*/
public <T extends AuthnMechanism> boolean hasMechanism(final Class<T> mechanismType) {
return !getMechanism(mechanismType).isEmpty();
}
/**
* Sets a configuration's parameters. The security manager uses this only for
* testing.
*
* @param params The new parameters.
*/
public void setParams(ConfigParams params) {
Preconditions.checkNotNull(params);
synchronized (this) {
this.params = params;
}
ConfigSingleton.setChanged();
}
/**
* @return The name of the ACL group rules file, never null or empty.
*/
public String getAclGroupsFilename() {
return params.get(ParamName.ACL_GROUPS_FILENAME, String.class);
}
/**
* @return The name of the ACL URL rules file, never null or empty.
*/
public String getAclUrlsFilename() {
return params.get(ParamName.ACL_URLS_FILENAME, String.class);
}
/**
* @return The name of the certificate-authority certificates file, never null
* or empty.
*/
public String getCertificateAuthoritiesFilename() {
return params.get(ParamName.CERTIFICATE_AUTHORITIES_FILENAME, String.class);
}
/**
* @return The boolean value whether to check the server certificate during
* serving time
*/
public Boolean getCheckServerCertificate() {
return params.get(ParamName.CHECK_SERVER_CERTIFICATE, Boolean.class);
}
/**
* @return The URLs of the configured connector managers as an immutable set.
*/
public StringSet getConnectorManagerUrls() {
return params.get(ParamName.CONNECTOR_MANAGER_URLS, StringSet.class);
}
/**
* @return The name of the http deny rules file, never null or empty.
*/
public String getDenyRulesFilename() {
return params.get(ParamName.DENY_RULES_FILENAME, String.class);
}
/**
* @return The global batch request timeout.
*/
public Float getGlobalBatchRequestTimeout() {
return params.get(ParamName.GLOBAL_BATCH_REQUEST_TIMEOUT, Float.class);
}
/**
* @return The global single request timeout.
*/
public Float getGlobalSingleRequestTimeout() {
return params.get(ParamName.GLOBAL_SINGLE_REQUEST_TIMEOUT, Float.class);
}
/**
* @return The name of the SAML metadata configuration file, never null or
* empty.
*/
public String getSamlMetadataFilename() {
return params.get(ParamName.SAML_METADATA_FILENAME, String.class);
}
/**
* @return The name of the security manager's certificate file, never null or
* empty.
*/
public String getServerCertificateFilename() {
return params.get(ParamName.SERVER_CERTIFICATE_FILENAME, String.class);
}
/**
* @return The name of the certificate file to be used for signing outgoing
* messages, never null or empty.
*/
public String getSigningCertificateFilename() {
return params.get(ParamName.SIGNING_CERTIFICATE_FILENAME, String.class);
}
/**
* @return The name of the key file to be used for signing outgoing messages,
* never null or empty.
*/
public String getSigningKeyFilename() {
return params.get(ParamName.SIGNING_KEY_FILENAME, String.class);
}
/**
* @return The port of the stunnel service that is forwarding to the security manager.
*/
public int getStunnelPort() {
return params.get(ParamName.STUNNEL_PORT, Integer.class);
}
@Override
public String toString() {
return ConfigSingleton.getGson().toJson(this);
}
@Override
public synchronized boolean equals(Object object) {
if (object == this) { return true; }
if (!(object instanceof SecurityManagerConfig)) { return false; }
SecurityManagerConfig other = (SecurityManagerConfig) object;
return Objects.equal(getVersion(), other.getVersion())
&& Objects.equal(getCredentialGroups(), other.getCredentialGroups())
&& Objects.equal(getParams(), other.getParams())
&& Objects.equal(getFlexAuthorizer(), other.getFlexAuthorizer());
}
@Override
public synchronized int hashCode() {
return Objects.hashCode(getVersion(), getCredentialGroups(), getParams(), getFlexAuthorizer());
}
static void registerTypeAdapters(GsonBuilder builder) {
builder.registerTypeAdapter(SecurityManagerConfig.class,
ProxyTypeAdapter.make(SecurityManagerConfig.class, LocalProxy.class));
builder.registerTypeAdapter(new TypeToken<ImmutableList<CredentialGroup>>() {}.getType(),
TypeAdapters.immutableList());
}
private static final class LocalProxy implements TypeProxy<SecurityManagerConfig> {
int version;
@SerializedName("CGs") ImmutableList<CredentialGroup> credentialGroups;
ConfigParams params;
@SerializedName("flexAuthz") FlexAuthorizer flexAuthorizer;
@SuppressWarnings("unused")
LocalProxy() {
}
@SuppressWarnings("unused")
LocalProxy(SecurityManagerConfig config) {
version = config.getVersion();
credentialGroups = config.getCredentialGroups();
params = config.getParams();
flexAuthorizer = config.getFlexAuthorizer();
}
@Override
public SecurityManagerConfig build() {
return makeInternal(version, credentialGroups, params, flexAuthorizer);
}
}
}