blob: f55d7b8ce5be2ec25103f386cd87c3e3411d1006 [file] [log] [blame]
/*
* 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.guacamole.auth.saml.conf;
import com.google.inject.Inject;
import com.onelogin.saml2.settings.IdPMetadataParser;
import com.onelogin.saml2.settings.Saml2Settings;
import com.onelogin.saml2.settings.SettingsBuilder;
import com.onelogin.saml2.util.Constants;
import java.io.File;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleServerException;
import org.apache.guacamole.environment.Environment;
import org.apache.guacamole.properties.BooleanGuacamoleProperty;
import org.apache.guacamole.properties.FileGuacamoleProperty;
import org.apache.guacamole.properties.StringGuacamoleProperty;
import org.apache.guacamole.properties.URIGuacamoleProperty;
/**
* Service for retrieving configuration information regarding the SAML
* authentication module.
*/
public class ConfigurationService {
/**
* The file containing the XML Metadata associated with the SAML IdP.
*/
private static final FileGuacamoleProperty SAML_IDP_METADATA =
new FileGuacamoleProperty() {
@Override
public String getName() { return "saml-idp-metadata"; }
};
/**
* The URL of the SAML IdP.
*/
private static final URIGuacamoleProperty SAML_IDP_URL =
new URIGuacamoleProperty() {
@Override
public String getName() { return "saml-idp-url"; }
};
/**
* The URL identifier for this SAML client.
*/
private static final URIGuacamoleProperty SAML_ENTITY_ID =
new URIGuacamoleProperty() {
@Override
public String getName() { return "saml-entity-id"; }
};
/**
* The callback URL to use for SAML IdP, normally the base
* of the Guacamole install. The SAML extensions callback
* endpoint will be appended to this value.
*/
private static final URIGuacamoleProperty SAML_CALLBACK_URL =
new URIGuacamoleProperty() {
@Override
public String getName() { return "saml-callback-url"; }
};
/**
* Whether or not debugging should be enabled in the SAML library to help
* track down errors.
*/
private static final BooleanGuacamoleProperty SAML_DEBUG =
new BooleanGuacamoleProperty() {
@Override
public String getName() { return "saml-debug"; }
};
/**
* Whether or not to enable compression for the SAML request.
*/
private static final BooleanGuacamoleProperty SAML_COMPRESS_REQUEST =
new BooleanGuacamoleProperty() {
@Override
public String getName() { return "saml-compress-request"; }
};
/**
* Whether or not to enable compression for the SAML response.
*/
private static final BooleanGuacamoleProperty SAML_COMPRESS_RESPONSE =
new BooleanGuacamoleProperty() {
@Override
public String getName() { return "saml-compress-response"; }
};
/**
* Whether or not to enforce strict SAML security during processing.
*/
private static final BooleanGuacamoleProperty SAML_STRICT =
new BooleanGuacamoleProperty() {
@Override
public String getName() { return "saml-strict"; }
};
/**
* The property that defines what attribute the SAML provider will return
* that contains group membership for the authenticated user.
*/
private static final StringGuacamoleProperty SAML_GROUP_ATTRIBUTE =
new StringGuacamoleProperty() {
@Override
public String getName() { return "saml-group-attribute"; }
};
/**
* The Guacamole server environment.
*/
@Inject
private Environment environment;
/**
* Returns the URL to be submitted as the client ID to the SAML IdP, as
* configured in guacamole.properties.
*
* @return
* The URL to send to the SAML IdP as the Client Identifier.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed, or if the
* property is missing.
*/
private URI getEntityId() throws GuacamoleException {
return environment.getRequiredProperty(SAML_ENTITY_ID);
}
/**
* The file that contains the metadata that the SAML client should
* use to communicate with the SAML IdP. This is generated by the
* SAML IdP and should be uploaded to the system where the Guacamole
* client is running.
*
* @return
* The file containing the metadata used by the SAML client
* when it communicates with the SAML IdP.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed, or if the client
* metadata is missing.
*/
private File getIdpMetadata() throws GuacamoleException {
return environment.getProperty(SAML_IDP_METADATA);
}
/**
* Return the URL used to log in to the SAML IdP.
*
* @return
* The URL used to log in to the SAML IdP.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
private URI getIdpUrl() throws GuacamoleException {
return environment.getProperty(SAML_IDP_URL);
}
/**
* The callback URL used for the SAML IdP to POST a response
* to upon completion of authentication, normally the base
* of the Guacamole install.
*
* @return
* The callback URL to be sent to the SAML IdP that will
* be POSTed to upon completion of SAML authentication.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed, or if the
* callback parameter is missing.
*/
public URI getCallbackUrl() throws GuacamoleException {
return environment.getRequiredProperty(SAML_CALLBACK_URL);
}
/**
* Return the Boolean value that indicates whether SAML client debugging
* will be enabled, as configured in guacamole.properties. The default is
* false, and debug information will not be generated or logged.
*
* @return
* True if debugging should be enabled in the SAML library, otherwise
* false.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
private boolean getDebug() throws GuacamoleException {
return environment.getProperty(SAML_DEBUG, false);
}
/**
* Return the Boolean value that indicates whether or not compression of
* SAML requests to the IdP should be enabled or not, as configured in
* guacamole.properties. The default is to enable compression.
*
* @return
* True if compression should be enabled when sending the SAML request,
* otherwise false.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
private boolean getCompressRequest() throws GuacamoleException {
return environment.getProperty(SAML_COMPRESS_REQUEST, true);
}
/**
* Return a Boolean value that indicates whether or not the SAML login
* should enforce strict security controls, as configured in
* guacamole.properties. By default this is true, and should be set to
* true in any production environment.
*
* @return
* True if the SAML login should enforce strict security checks,
* otherwise false.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
private boolean getStrict() throws GuacamoleException {
return environment.getProperty(SAML_STRICT, true);
}
/**
* Return a Boolean value that indicates whether or not compression should
* be requested from the server when the SAML response is returned, as
* configured in guacamole.properties. The default is to request that the
* response be compressed.
*
* @return
* True if compression should be requested from the server for the SAML
* response.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
private boolean getCompressResponse() throws GuacamoleException {
return environment.getProperty(SAML_COMPRESS_RESPONSE, true);
}
/**
* Return the name of the attribute that will be supplied by the identity
* provider that contains the groups of which this user is a member.
*
* @return
* The name of the attribute that contains the user groups.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
public String getGroupAttribute() throws GuacamoleException {
return environment.getProperty(SAML_GROUP_ATTRIBUTE, "groups");
}
/**
* Returns the collection of SAML settings used to initialize the client.
*
* @return
* The collection of SAML settings used to initialize the SAML client.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed or if required parameters
* are missing.
*/
public Saml2Settings getSamlSettings() throws GuacamoleException {
// Try to get the XML file, first.
File idpMetadata = getIdpMetadata();
Map<String, Object> samlMap;
if (idpMetadata != null) {
try {
samlMap = IdPMetadataParser.parseFileXML(idpMetadata.getAbsolutePath());
}
catch (Exception e) {
throw new GuacamoleServerException(
"Could not parse SAML IdP Metadata file.", e);
}
}
// If no XML metadata is provided, fall-back to individual values.
else {
samlMap = new HashMap<>();
samlMap.put(SettingsBuilder.IDP_ENTITYID_PROPERTY_KEY,
getIdpUrl().toString());
samlMap.put(SettingsBuilder.IDP_SINGLE_SIGN_ON_SERVICE_URL_PROPERTY_KEY,
getIdpUrl().toString());
samlMap.put(SettingsBuilder.IDP_SINGLE_SIGN_ON_SERVICE_BINDING_PROPERTY_KEY,
Constants.BINDING_HTTP_REDIRECT);
}
// Common settings, required with or without metadata file.
samlMap.put(SettingsBuilder.SP_ENTITYID_PROPERTY_KEY,
getEntityId().toString());
samlMap.put(SettingsBuilder.SP_ASSERTION_CONSUMER_SERVICE_URL_PROPERTY_KEY,
getCallbackUrl().toString() + "/api/ext/saml/callback");
SettingsBuilder samlBuilder = new SettingsBuilder();
Saml2Settings samlSettings = samlBuilder.fromValues(samlMap).build();
samlSettings.setStrict(getStrict());
samlSettings.setDebug(getDebug());
samlSettings.setCompressRequest(getCompressRequest());
samlSettings.setCompressResponse(getCompressResponse());
return samlSettings;
}
}