You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@guacamole.apache.org by necouchman <gi...@git.apache.org> on 2018/02/16 20:04:20 UTC

[GitHub] guacamole-client pull request #254: GUACAMOLE-103: Implement SAML Authentica...

GitHub user necouchman opened a pull request:

    https://github.com/apache/guacamole-client/pull/254

    GUACAMOLE-103: Implement SAML Authentication Extension

    Initial cut at a SAML authentication extension.  Plenty of room for improvement, I'm sure - I welcome all comments/suggestions/changes.  I'll kick off my own review, here, shortly.

You can merge this pull request into a Git repository by running:

    $ git pull https://github.com/necouchman/guacamole-client GUACAMOLE-103

Alternatively you can review and apply these changes as the patch at:

    https://github.com/apache/guacamole-client/pull/254.patch

To close this pull request, make a commit to your master/trunk branch
with (at least) the following in the commit message:

    This closes #254
    
----
commit 444ac702a4c1486e5b23620ec328b5dfa2e3836a
Author: Nick Couchman <vn...@...>
Date:   2018-02-14T18:26:08Z

    GUACAMOLE-103: Implement URL property type.

commit 7b016d3a2155e9f2427c7a93f3f91eecb6c6b4be
Author: Nick Couchman <vn...@...>
Date:   2017-11-02T19:06:39Z

    GUACAMOLE-103: Implementation of SAML authentication extension, using OpenID as a template.

commit d236e1304b781cd4a34a8f1ff640e074d58d9e7b
Author: Nick Couchman <vn...@...>
Date:   2018-02-16T18:47:14Z

    GUACAMOLE-103: Code cleanup - fix style issues, remove debug.

commit 33f0ba36be4399471e004ce52ab7a7ec520db40f
Author: Nick Couchman <vn...@...>
Date:   2018-02-16T19:59:51Z

    GUACAMOLE-103: Minimal validation for SAML response.

----


---

[GitHub] guacamole-client pull request #254: GUACAMOLE-103: Implement SAML Authentica...

Posted by necouchman <gi...@git.apache.org>.
Github user necouchman commented on a diff in the pull request:

    https://github.com/apache/guacamole-client/pull/254#discussion_r168859198
  
    --- Diff: extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java ---
    @@ -0,0 +1,223 @@
    +/*
    + * 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.Saml2Settings;
    +import com.onelogin.saml2.settings.SettingsBuilder;
    +import java.io.File;
    +import java.net.URL;
    +import java.util.HashMap;
    +import java.util.Map;
    +import org.apache.guacamole.GuacamoleException;
    +import org.apache.guacamole.environment.Environment;
    +import org.apache.guacamole.properties.FileGuacamoleProperty;
    +import org.apache.guacamole.properties.StringGuacamoleProperty;
    +import org.apache.guacamole.properties.UrlGuacamoleProperty;
    +
    +/**
    + * 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"; }
    --- End diff --
    
    Unfortunately this option has no effect right now, because the OneLogin SAML client has not released the version that implements pulling settings from the IdP Metadata.  Hopefully it'll be out, soon, but the lead developer hasn't been very responsive.


---

[GitHub] guacamole-client pull request #254: GUACAMOLE-103: Implement SAML Authentica...

Posted by necouchman <gi...@git.apache.org>.
Github user necouchman commented on a diff in the pull request:

    https://github.com/apache/guacamole-client/pull/254#discussion_r168859768
  
    --- Diff: guacamole-ext/src/main/java/org/apache/guacamole/properties/UrlGuacamoleProperty.java ---
    @@ -0,0 +1,48 @@
    +/*
    + * 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.properties;
    +
    +import java.net.MalformedURLException;
    +import java.net.URL;
    +import org.apache.guacamole.GuacamoleException;
    +import org.apache.guacamole.GuacamoleServerException;
    +
    +/**
    + * A GuacamoleProperty whose value is a URL.
    + */
    +public abstract class UrlGuacamoleProperty implements GuacamoleProperty<URL> {
    --- End diff --
    
    I went ahead and put this as a `guacamole-ext` property, as it seems like this might be useful outside of just this extension.


---

[GitHub] guacamole-client pull request #254: GUACAMOLE-103: Implement SAML Authentica...

Posted by necouchman <gi...@git.apache.org>.
Github user necouchman commented on a diff in the pull request:

    https://github.com/apache/guacamole-client/pull/254#discussion_r168859369
  
    --- Diff: extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java ---
    @@ -0,0 +1,223 @@
    +/*
    + * 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.Saml2Settings;
    +import com.onelogin.saml2.settings.SettingsBuilder;
    +import java.io.File;
    +import java.net.URL;
    +import java.util.HashMap;
    +import java.util.Map;
    +import org.apache.guacamole.GuacamoleException;
    +import org.apache.guacamole.environment.Environment;
    +import org.apache.guacamole.properties.FileGuacamoleProperty;
    +import org.apache.guacamole.properties.StringGuacamoleProperty;
    +import org.apache.guacamole.properties.UrlGuacamoleProperty;
    +
    +/**
    + * 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 UrlGuacamoleProperty SAML_IDP_URL =
    +            new UrlGuacamoleProperty() {
    +
    +        @Override
    +        public String getName() { return "saml-idp-url"; }
    +
    +    };
    +
    +    /**
    +     * The identifier for this SAML client.  The default is
    +     * "Apache Guacamole"
    +     */
    +    private static final StringGuacamoleProperty SAML_ENTITY_ID =
    +            new StringGuacamoleProperty() {
    +
    +        @Override
    +        public String getName() { return "saml-entity-id"; }
    +
    +    };
    +
    +    /**
    +     * The callback URL to use for SAML IdP, normally the base
    +     * of the Guacamole install.
    +     */
    +    private static final UrlGuacamoleProperty SAML_CALLBACK_URL =
    +            new UrlGuacamoleProperty() {
    +
    +        @Override
    +        public String getName() { return "saml-callback-url"; }
    +
    +    };
    +
    +    /**
    +     * The single logout redirect URL.
    +     */
    +    private static final UrlGuacamoleProperty SAML_LOGOUT_URL =
    +            new UrlGuacamoleProperty() {
    +
    +        @Override
    +        public String getName() { return "saml-logout-url"; }
    +
    +    };
    +
    +    /**
    +     * The Guacamole server environment.
    +     */
    +    @Inject
    +    private Environment environment;
    +
    +    /**
    +     * Returns the client ID which should be submitted to the SAML IdP,
    +     * as configured with guacamole.properties.  The default value is
    +     * "Apache Guacamole".
    +     *
    +     * @return
    +     *     The client ID to use when communicating with the SAML IdP,
    +     *     as configured with guacamole.properties, or the default
    +     *     of "Apache Guacamole" if not specified.
    +     *
    +     * @throws GuacamoleException
    +     *     If guacamole.properties cannot be parsed, or if the client ID
    +     *     property is missing.
    +     */
    +    private String getEntityId() throws GuacamoleException {
    +        return environment.getProperty(
    +            SAML_ENTITY_ID,
    +            "Apache Guacamole"
    --- End diff --
    
    This needs to be changed - it looks like the Entity ID should actually be a URL of some sort.


---

[GitHub] guacamole-client pull request #254: GUACAMOLE-103: Implement SAML Authentica...

Posted by necouchman <gi...@git.apache.org>.
Github user necouchman commented on a diff in the pull request:

    https://github.com/apache/guacamole-client/pull/254#discussion_r168858953
  
    --- Diff: extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderResource.java ---
    @@ -0,0 +1,76 @@
    +/*
    + * 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;
    +
    +import com.google.inject.Inject;
    +import com.onelogin.saml2.util.Util;
    +import java.net.URI;
    +import java.net.URISyntaxException;
    +import javax.ws.rs.core.Response;
    +import javax.ws.rs.FormParam;
    +import javax.ws.rs.Path;
    +import javax.ws.rs.POST;
    +import org.apache.guacamole.GuacamoleException;
    +import org.apache.guacamole.GuacamoleServerException;
    +import org.apache.guacamole.auth.saml.conf.ConfigurationService;
    +import org.slf4j.Logger;
    +import org.slf4j.LoggerFactory;
    +
    +/**
    + * A class that implements the REST API necessary for the
    + * SAML Idp to POST back its response to Guacamole.
    + */
    +public class SAMLAuthenticationProviderResource {
    +
    +    /**
    +     * The Logger for the class.
    +     */
    +    private final Logger logger = LoggerFactory.getLogger(SAMLAuthenticationProviderResource.class); 
    +
    +    /**
    +     * The configuration service for this module.
    +     */
    +    @Inject
    +    private ConfigurationService confService;
    +
    +    /**
    +     * A REST endpoint that is POSTed to by the SAML Idp
    +     * with the results of the SAML SSO Authentication.
    +     */
    +    @POST
    +    @Path("callback")
    +    public Response processSamlResponse(@FormParam("SAMLResponse") String samlResponse)
    +            throws GuacamoleException {
    +
    +        String guacBase = confService.getCallbackUrl().toString();
    +        try {
    +            Response redirectHome = Response.seeOther(
    +                new URI(guacBase + "?SAMLResponse=" + Util.urlEncoder(samlResponse))).build();
    +            return redirectHome;
    --- End diff --
    
    This works okay; however, this redirect tends to cause issues with header size in my testing - I'm using the CAS SAML IdP, and I had to bump up the maxHttpHeaderSize on Tomcat and then the proxy_buffer_size and proxy_busy_buffers_size parameter in Nginx to get this to work.  It does work reliably, but not sure if this is the best way to go, or if I should try to process the SAML response directly in here?


---

[GitHub] guacamole-client pull request #254: GUACAMOLE-103: Implement SAML Authentica...

Posted by necouchman <gi...@git.apache.org>.
Github user necouchman commented on a diff in the pull request:

    https://github.com/apache/guacamole-client/pull/254#discussion_r168861891
  
    --- Diff: extensions/guacamole-auth-saml/src/licenses/bundled/saml-client-1.2.0/LICENSE ---
    @@ -0,0 +1,20 @@
    +The MIT License (MIT)
    +Copyright (c) 2016 Coveo
    +
    +Permission is hereby granted, free of charge, to any person obtaining a
    +copy of this software and associated documentation files (the "Software"),
    +to deal in the Software without restriction, including without limitation
    +the rights to use, copy, modify, merge, publish, distribute, sublicense,
    +and/or sell copies of the Software, and to permit persons to whom the
    +Software is furnished to do so, subject to the following conditions:
    +
    +    The above copyright notice and this permission notice shall be
    +    included in all copies or substantial portions of the Software.
    +
    +    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    +    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    +    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    +    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    +    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
    +    IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
    +    IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    --- End diff --
    
    Wrong SAML client.


---

[GitHub] guacamole-client pull request #254: GUACAMOLE-103: Implement SAML Authentica...

Posted by necouchman <gi...@git.apache.org>.
Github user necouchman commented on a diff in the pull request:

    https://github.com/apache/guacamole-client/pull/254#discussion_r168859454
  
    --- Diff: extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java ---
    @@ -0,0 +1,223 @@
    +/*
    + * 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.Saml2Settings;
    +import com.onelogin.saml2.settings.SettingsBuilder;
    +import java.io.File;
    +import java.net.URL;
    +import java.util.HashMap;
    +import java.util.Map;
    +import org.apache.guacamole.GuacamoleException;
    +import org.apache.guacamole.environment.Environment;
    +import org.apache.guacamole.properties.FileGuacamoleProperty;
    +import org.apache.guacamole.properties.StringGuacamoleProperty;
    +import org.apache.guacamole.properties.UrlGuacamoleProperty;
    +
    +/**
    + * 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 UrlGuacamoleProperty SAML_IDP_URL =
    +            new UrlGuacamoleProperty() {
    +
    +        @Override
    +        public String getName() { return "saml-idp-url"; }
    +
    +    };
    +
    +    /**
    +     * The identifier for this SAML client.  The default is
    +     * "Apache Guacamole"
    +     */
    +    private static final StringGuacamoleProperty SAML_ENTITY_ID =
    +            new StringGuacamoleProperty() {
    +
    +        @Override
    +        public String getName() { return "saml-entity-id"; }
    +
    +    };
    +
    +    /**
    +     * The callback URL to use for SAML IdP, normally the base
    +     * of the Guacamole install.
    +     */
    +    private static final UrlGuacamoleProperty SAML_CALLBACK_URL =
    +            new UrlGuacamoleProperty() {
    +
    +        @Override
    +        public String getName() { return "saml-callback-url"; }
    +
    +    };
    +
    +    /**
    +     * The single logout redirect URL.
    +     */
    +    private static final UrlGuacamoleProperty SAML_LOGOUT_URL =
    +            new UrlGuacamoleProperty() {
    +
    +        @Override
    +        public String getName() { return "saml-logout-url"; }
    +
    +    };
    +
    +    /**
    +     * The Guacamole server environment.
    +     */
    +    @Inject
    +    private Environment environment;
    +
    +    /**
    +     * Returns the client ID which should be submitted to the SAML IdP,
    +     * as configured with guacamole.properties.  The default value is
    +     * "Apache Guacamole".
    +     *
    +     * @return
    +     *     The client ID to use when communicating with the SAML IdP,
    +     *     as configured with guacamole.properties, or the default
    +     *     of "Apache Guacamole" if not specified.
    +     *
    +     * @throws GuacamoleException
    +     *     If guacamole.properties cannot be parsed, or if the client ID
    +     *     property is missing.
    +     */
    +    private String getEntityId() throws GuacamoleException {
    +        return environment.getProperty(
    +            SAML_ENTITY_ID,
    +            "Apache Guacamole"
    +        );
    +    }
    +
    +    /**
    +     * 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 containinging the metadata used by the SAML client
    +     *     when it communicates with the SAML IdP.
    +     *
    +     * @throws GuacamoleException
    +     *     If guacmaole.propeties cannot be parsed, or if the client
    +     *     metadata is missing.
    +     */
    +    private File getIdpMetadata() throws GuacamoleException {
    +        return environment.getRequiredProperty(SAML_IDP_METADATA);
    +    }
    +
    +    /**
    +     * Retrieve 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 URL getIdpUrl() throws GuacamoleException {
    +        return environment.getProperty(
    +            SAML_IDP_URL,
    +            null
    +        );
    +    }
    +
    +    /**
    +     * 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 URL getCallbackUrl() throws GuacamoleException {
    +        return environment.getRequiredProperty(SAML_CALLBACK_URL);
    +    }
    +
    +    /**
    +     * Return the URL used to log out from the SAML IdP.
    +     *
    +     * @return
    +     *     The URL used to log out from the SAML IdP.
    +     *
    +     * @throws GuacamoleException
    +     *     If guacamole.properties cannot be parsed.
    +     */
    +    private URL getLogoutUrl() throws GuacamoleException {
    +        return environment.getProperty(
    +            SAML_LOGOUT_URL,
    +            null
    +        );
    +    }
    +
    +    /**
    +     * Returns the collection of SAML settings used to
    +     * initialize the client.
    +     *
    +     * @return
    +     *     The collection of SAML settings used to 
    +     *     initalize the SAML client.
    +     *
    +     * @throws GuacamoleException
    +     *     If guacamole.properties cannot be parsed or
    +     *     if parameters are missing.
    +     */
    +    public Saml2Settings getSamlSettings() throws GuacamoleException {
    +
    +        // Initialize and configure SAML client.
    +        Map<String, Object> samlMap = new HashMap<String, Object>();
    +        samlMap.put("onelogin.saml2.sp.entityid", getEntityId());
    +        samlMap.put("onelogin.saml2.sp.assertion_consumer_service.url", getCallbackUrl() + "/api/ext/saml/callback");
    +        samlMap.put("onelogin.saml2.idp.entityid", getIdpUrl());
    +        samlMap.put("onelogin.saml2.idp.single_sign_on_service.url", getIdpUrl());
    +        samlMap.put("onelogin.saml2.idp.single_sign_on_sevice.binding", "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect");
    --- End diff --
    
    Not sure if I can use constants here??


---

[GitHub] guacamole-client pull request #254: GUACAMOLE-103: Implement SAML Authentica...

Posted by necouchman <gi...@git.apache.org>.
Github user necouchman commented on a diff in the pull request:

    https://github.com/apache/guacamole-client/pull/254#discussion_r168858220
  
    --- Diff: extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java ---
    @@ -0,0 +1,202 @@
    +/*
    + * 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;
    +
    +import com.google.inject.Inject;
    +import com.google.inject.Provider;
    +import com.onelogin.saml2.authn.AuthnRequest;
    +import com.onelogin.saml2.authn.SamlResponse;
    +import com.onelogin.saml2.exception.SettingsException;
    +import com.onelogin.saml2.exception.ValidationError;
    +import com.onelogin.saml2.http.HttpRequest;
    +import com.onelogin.saml2.servlet.ServletUtils;
    +import com.onelogin.saml2.settings.Saml2Settings;
    +import com.onelogin.saml2.util.Util;
    +import java.io.IOException;
    +import java.util.Arrays;
    +import javax.servlet.http.HttpServletRequest;
    +import javax.xml.parsers.ParserConfigurationException;
    +import javax.xml.xpath.XPathExpressionException;
    +import org.apache.guacamole.auth.saml.conf.ConfigurationService;
    +import org.apache.guacamole.auth.saml.form.SAMLRedirectField;
    +import org.apache.guacamole.auth.saml.user.AuthenticatedUser;
    +import org.apache.guacamole.GuacamoleException;
    +import org.apache.guacamole.form.Field;
    +import org.apache.guacamole.net.auth.Credentials;
    +import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
    +import org.apache.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException;
    +import org.apache.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException;
    +import org.slf4j.Logger;
    +import org.slf4j.LoggerFactory;
    +import org.xml.sax.SAXException;
    +
    +/**
    + * Class that provides services for use by the SAML Authentication Provider class.
    + */
    +public class AuthenticationProviderService {
    +
    +    /**
    +     * Logger for this class.
    +     */
    +    private final Logger logger = LoggerFactory.getLogger(AuthenticationProviderService.class);
    +
    +    /**
    +     * Service for retrieving SAML configuration information.
    +     */
    +    @Inject
    +    private ConfigurationService confService;
    +
    +    /**
    +     * Provider for AuthenticatedUser objects.
    +     */
    +    @Inject
    +    private Provider<AuthenticatedUser> authenticatedUserProvider;
    +
    +    /**
    +     * Returns an AuthenticatedUser representing the user authenticated by the
    +     * given credentials.
    +     *
    +     * @param credentials
    +     *     The credentials to use for authentication.
    +     *
    +     * @return
    +     *     An AuthenticatedUser representing the user authenticated by the
    +     *     given credentials.
    +     *
    +     * @throws GuacamoleException
    +     *     If an error occurs while authenticating the user, or if access is
    +     *     denied.
    +     */
    +    public AuthenticatedUser authenticateUser(Credentials credentials)
    +            throws GuacamoleException {
    +
    +        HttpServletRequest request = credentials.getRequest();
    +
    +        // Initialize and configure SAML client.
    +        Saml2Settings samlSettings = confService.getSamlSettings();
    +
    +        if (request != null) {
    +            
    +            // Look for the SAML Response parameter.
    +            String samlResponseParam = request.getParameter("SAMLResponse");
    +
    +            if (samlResponseParam != null) {
    +
    +                // Convert the SAML response into the version needed for the client.
    +                HttpRequest httpRequest = ServletUtils.makeHttpRequest(request);
    +                try {
    +
    +                    // Generate the response object
    +                    SamlResponse samlResponse = new SamlResponse(samlSettings, httpRequest);
    +
    +                    if (!samlResponse.validateNumAssertions()) {
    +                        logger.warn("SAML response contained other than single assertion.");
    +                        logger.debug("validateNumAssertions returned false.");
    +                        throw new GuacamoleInvalidCredentialsException("Error during SAML login.",
    +                                CredentialsInfo.USERNAME_PASSWORD);
    +                    }
    +                    if (!samlResponse.validateTimestamps()) {
    +                        logger.warn("SAML response timestamps were invalid.");
    +                        logger.debug("validateTimestamps returned false.");
    +                        throw new GuacamoleInvalidCredentialsException("Error during SAML login.",
    +                                CredentialsInfo.USERNAME_PASSWORD);
    +                    }
    +
    +                    // Grab the username, and, if present, finish authentication.
    +                    String username = samlResponse.getNameId().toLowerCase();
    +                    if (username != null) {
    +                        credentials.setUsername(username);
    +                        AuthenticatedUser authenticatedUser = authenticatedUserProvider.get();
    +                        authenticatedUser.init(username, credentials);
    +                        return authenticatedUser;
    +                    }
    +                }
    +
    +                // Errors are logged and result in a normal username/password login box.
    +                catch (IOException e) {
    +                    logger.warn("Error during I/O while parsing SAML response: {}", e.getMessage());
    +                    logger.debug("Received IOException when trying to parse SAML response.", e);
    +                    throw new GuacamoleInvalidCredentialsException("Error during SAML login.",
    +                                CredentialsInfo.USERNAME_PASSWORD);
    +                }
    +                catch (ParserConfigurationException e) {
    +                    logger.warn("Error configuring XML parser: {}", e.getMessage());
    +                    logger.debug("Received ParserConfigurationException when trying to parse SAML response.", e);
    +                    throw new GuacamoleInvalidCredentialsException("Error during SAML login.",
    +                                CredentialsInfo.USERNAME_PASSWORD);
    +                }
    +                catch (SAXException e) {
    +                    logger.warn("Bad XML when parsing SAML response: {}", e.getMessage());
    +                    logger.debug("Received SAXException while parsing SAML response.", e);
    +                    throw new GuacamoleInvalidCredentialsException("Error during SAML login.",
    +                                CredentialsInfo.USERNAME_PASSWORD);
    +                }
    +                catch (SettingsException e) {
    +                    logger.warn("Error with SAML settings while parsing response: {}", e.getMessage());
    +                    logger.debug("Received SettingsException while parsing SAML response.", e);
    +                    throw new GuacamoleInvalidCredentialsException("Error during SAML login.",
    +                                CredentialsInfo.USERNAME_PASSWORD);
    +                }
    +                catch (ValidationError e) {
    +                    logger.warn("Error validating SAML response: {}", e.getMessage());
    +                    logger.debug("Received ValidationError while parsing SAML response.", e);
    +                    throw new GuacamoleInvalidCredentialsException("Error during SAML login.",
    +                                CredentialsInfo.USERNAME_PASSWORD);
    +                }
    +                catch (XPathExpressionException e) {
    +                    logger.warn("Problem with XML parsing response: {}", e.getMessage());
    +                    logger.debug("Received XPathExpressionException while processing SAML response.", e);
    +                    throw new GuacamoleInvalidCredentialsException("Error during SAML login.",
    +                                CredentialsInfo.USERNAME_PASSWORD);
    +                }
    +                catch (Exception e) {
    +                    logger.warn("Exception while getting name from SAML response: {}", e.getMessage());
    +                    logger.debug("Received Exception while retrieving name from SAML response.", e);
    +                    throw new GuacamoleInvalidCredentialsException("Error during SAML login.",
    +                                CredentialsInfo.USERNAME_PASSWORD);
    +                }
    --- End diff --
    
    Wow, this is nasty.  Unfortunately the SAML client doesn't currently capture exceptions it generates, so we have to do it, here.


---

[GitHub] guacamole-client pull request #254: GUACAMOLE-103: Implement SAML Authentica...

Posted by necouchman <gi...@git.apache.org>.
Github user necouchman commented on a diff in the pull request:

    https://github.com/apache/guacamole-client/pull/254#discussion_r168861782
  
    --- Diff: extensions/guacamole-auth-saml/src/licenses/LICENSE ---
    @@ -0,0 +1,257 @@
    +
    +                                 Apache License
    +                           Version 2.0, January 2004
    +                        http://www.apache.org/licenses/
    +
    +   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
    +
    +   1. Definitions.
    +
    +      "License" shall mean the terms and conditions for use, reproduction,
    +      and distribution as defined by Sections 1 through 9 of this document.
    +
    +      "Licensor" shall mean the copyright owner or entity authorized by
    +      the copyright owner that is granting the License.
    +
    +      "Legal Entity" shall mean the union of the acting entity and all
    +      other entities that control, are controlled by, or are under common
    +      control with that entity. For the purposes of this definition,
    +      "control" means (i) the power, direct or indirect, to cause the
    +      direction or management of such entity, whether by contract or
    +      otherwise, or (ii) ownership of fifty percent (50%) or more of the
    +      outstanding shares, or (iii) beneficial ownership of such entity.
    +
    +      "You" (or "Your") shall mean an individual or Legal Entity
    +      exercising permissions granted by this License.
    +
    +      "Source" form shall mean the preferred form for making modifications,
    +      including but not limited to software source code, documentation
    +      source, and configuration files.
    +
    +      "Object" form shall mean any form resulting from mechanical
    +      transformation or translation of a Source form, including but
    +      not limited to compiled object code, generated documentation,
    +      and conversions to other media types.
    +
    +      "Work" shall mean the work of authorship, whether in Source or
    +      Object form, made available under the License, as indicated by a
    +      copyright notice that is included in or attached to the work
    +      (an example is provided in the Appendix below).
    +
    +      "Derivative Works" shall mean any work, whether in Source or Object
    +      form, that is based on (or derived from) the Work and for which the
    +      editorial revisions, annotations, elaborations, or other modifications
    +      represent, as a whole, an original work of authorship. For the purposes
    +      of this License, Derivative Works shall not include works that remain
    +      separable from, or merely link (or bind by name) to the interfaces of,
    +      the Work and Derivative Works thereof.
    +
    +      "Contribution" shall mean any work of authorship, including
    +      the original version of the Work and any modifications or additions
    +      to that Work or Derivative Works thereof, that is intentionally
    +      submitted to Licensor for inclusion in the Work by the copyright owner
    +      or by an individual or Legal Entity authorized to submit on behalf of
    +      the copyright owner. For the purposes of this definition, "submitted"
    +      means any form of electronic, verbal, or written communication sent
    +      to the Licensor or its representatives, including but not limited to
    +      communication on electronic mailing lists, source code control systems,
    +      and issue tracking systems that are managed by, or on behalf of, the
    +      Licensor for the purpose of discussing and improving the Work, but
    +      excluding communication that is conspicuously marked or otherwise
    +      designated in writing by the copyright owner as "Not a Contribution."
    +
    +      "Contributor" shall mean Licensor and any individual or Legal Entity
    +      on behalf of whom a Contribution has been received by Licensor and
    +      subsequently incorporated within the Work.
    +
    +   2. Grant of Copyright License. Subject to the terms and conditions of
    +      this License, each Contributor hereby grants to You a perpetual,
    +      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
    +      copyright license to reproduce, prepare Derivative Works of,
    +      publicly display, publicly perform, sublicense, and distribute the
    +      Work and such Derivative Works in Source or Object form.
    +
    +   3. Grant of Patent License. Subject to the terms and conditions of
    +      this License, each Contributor hereby grants to You a perpetual,
    +      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
    +      (except as stated in this section) patent license to make, have made,
    +      use, offer to sell, sell, import, and otherwise transfer the Work,
    +      where such license applies only to those patent claims licensable
    +      by such Contributor that are necessarily infringed by their
    +      Contribution(s) alone or by combination of their Contribution(s)
    +      with the Work to which such Contribution(s) was submitted. If You
    +      institute patent litigation against any entity (including a
    +      cross-claim or counterclaim in a lawsuit) alleging that the Work
    +      or a Contribution incorporated within the Work constitutes direct
    +      or contributory patent infringement, then any patent licenses
    +      granted to You under this License for that Work shall terminate
    +      as of the date such litigation is filed.
    +
    +   4. Redistribution. You may reproduce and distribute copies of the
    +      Work or Derivative Works thereof in any medium, with or without
    +      modifications, and in Source or Object form, provided that You
    +      meet the following conditions:
    +
    +      (a) You must give any other recipients of the Work or
    +          Derivative Works a copy of this License; and
    +
    +      (b) You must cause any modified files to carry prominent notices
    +          stating that You changed the files; and
    +
    +      (c) You must retain, in the Source form of any Derivative Works
    +          that You distribute, all copyright, patent, trademark, and
    +          attribution notices from the Source form of the Work,
    +          excluding those notices that do not pertain to any part of
    +          the Derivative Works; and
    +
    +      (d) If the Work includes a "NOTICE" text file as part of its
    +          distribution, then any Derivative Works that You distribute must
    +          include a readable copy of the attribution notices contained
    +          within such NOTICE file, excluding those notices that do not
    +          pertain to any part of the Derivative Works, in at least one
    +          of the following places: within a NOTICE text file distributed
    +          as part of the Derivative Works; within the Source form or
    +          documentation, if provided along with the Derivative Works; or,
    +          within a display generated by the Derivative Works, if and
    +          wherever such third-party notices normally appear. The contents
    +          of the NOTICE file are for informational purposes only and
    +          do not modify the License. You may add Your own attribution
    +          notices within Derivative Works that You distribute, alongside
    +          or as an addendum to the NOTICE text from the Work, provided
    +          that such additional attribution notices cannot be construed
    +          as modifying the License.
    +
    +      You may add Your own copyright statement to Your modifications and
    +      may provide additional or different license terms and conditions
    +      for use, reproduction, or distribution of Your modifications, or
    +      for any such Derivative Works as a whole, provided Your use,
    +      reproduction, and distribution of the Work otherwise complies with
    +      the conditions stated in this License.
    +
    +   5. Submission of Contributions. Unless You explicitly state otherwise,
    +      any Contribution intentionally submitted for inclusion in the Work
    +      by You to the Licensor shall be under the terms and conditions of
    +      this License, without any additional terms or conditions.
    +      Notwithstanding the above, nothing herein shall supersede or modify
    +      the terms of any separate license agreement you may have executed
    +      with Licensor regarding such Contributions.
    +
    +   6. Trademarks. This License does not grant permission to use the trade
    +      names, trademarks, service marks, or product names of the Licensor,
    +      except as required for reasonable and customary use in describing the
    +      origin of the Work and reproducing the content of the NOTICE file.
    +
    +   7. Disclaimer of Warranty. Unless required by applicable law or
    +      agreed to in writing, Licensor provides the Work (and each
    +      Contributor provides its Contributions) on an "AS IS" BASIS,
    +      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    +      implied, including, without limitation, any warranties or conditions
    +      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
    +      PARTICULAR PURPOSE. You are solely responsible for determining the
    +      appropriateness of using or redistributing the Work and assume any
    +      risks associated with Your exercise of permissions under this License.
    +
    +   8. Limitation of Liability. In no event and under no legal theory,
    +      whether in tort (including negligence), contract, or otherwise,
    +      unless required by applicable law (such as deliberate and grossly
    +      negligent acts) or agreed to in writing, shall any Contributor be
    +      liable to You for damages, including any direct, indirect, special,
    +      incidental, or consequential damages of any character arising as a
    +      result of this License or out of the use or inability to use the
    +      Work (including but not limited to damages for loss of goodwill,
    +      work stoppage, computer failure or malfunction, or any and all
    +      other commercial damages or losses), even if such Contributor
    +      has been advised of the possibility of such damages.
    +
    +   9. Accepting Warranty or Additional Liability. While redistributing
    +      the Work or Derivative Works thereof, You may choose to offer,
    +      and charge a fee for, acceptance of support, warranty, indemnity,
    +      or other liability obligations and/or rights consistent with this
    +      License. However, in accepting such obligations, You may act only
    +      on Your own behalf and on Your sole responsibility, not on behalf
    +      of any other Contributor, and only if You agree to indemnify,
    +      defend, and hold each Contributor harmless for any liability
    +      incurred by, or claims asserted against, such Contributor by reason
    +      of your accepting any such warranty or additional liability.
    +
    +   END OF TERMS AND CONDITIONS
    +
    +   APPENDIX: How to apply the Apache License to your work.
    +
    +      To apply the Apache License to your work, attach the following
    +      boilerplate notice, with the fields enclosed by brackets "[]"
    +      replaced with your own identifying information. (Don't include
    +      the brackets!)  The text should be enclosed in the appropriate
    +      comment syntax for the file format. We also recommend that a
    +      file or class name and description of purpose be included on the
    +      same "printed page" as the copyright notice for easier
    +      identification within third-party archives.
    +
    +   Copyright [yyyy] [name of copyright owner]
    +
    +   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.
    +
    +
    +==============================================================================
    +
    +APACHE GUACAMOLE SUBCOMPONENTS
    +
    +Apache Guacamole includes a number of subcomponents with separate copyright
    +notices and license terms. Your use of these subcomponents is subject to the
    +terms and conditions of the following licenses.
    +
    +
    +AOP Alliance (http://aopalliance.sourceforge.net/)
    +--------------------------------------------------
    +
    +    Version: 1.0
    +    From: 'AOP Alliance' (http://aopalliance.sourceforge.net/members.html)
    +    License(s):
    +        Public Domain (bundled/aopalliance-1.0/LICENSE)
    +
    +
    +Google Guice (https://github.com/google/guice)
    +----------------------------------------------
    +
    +    Version: 3.0
    +    From: 'Google Inc.' (http://www.google.com/)
    +    License(s):
    +        Apache v2.0 (bundled/guice-3.0/COPYING)
    +
    +
    +jose.4.j (https://bitbucket.org/b_c/jose4j/)
    +--------------------------------------------
    +
    +    Version: 0.5.5
    +    From: 'Brian Campbell' (https://bitbucket.org/b_c/)
    +    License(s):
    +        Apache v2.0 (bundled/jose4j-0.5.5/LICENSE)
    +
    +
    +JSR-330 / Dependency Injection for Java (http://code.google.com/p/atinject/)
    +----------------------------------------------------------------------------
    +
    +    Version: 1
    +    From: 'JSR-330 Expert Group' (https://jcp.org/en/jsr/detail?id=330)
    +    License(s):
    +        Apache v2.0 (bundled/javax.inject-1/LICENSE-2.0.txt)
    +
    +
    +Coveo Dead Simple SAML 2.0 Client (https://github.com/coveo/saml-client)
    --- End diff --
    
    Oops, wrong client...


---

[GitHub] guacamole-client pull request #254: GUACAMOLE-103: Implement SAML Authentica...

Posted by necouchman <gi...@git.apache.org>.
Github user necouchman commented on a diff in the pull request:

    https://github.com/apache/guacamole-client/pull/254#discussion_r198765764
  
    --- Diff: extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java ---
    @@ -0,0 +1,223 @@
    +/*
    + * 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.Saml2Settings;
    +import com.onelogin.saml2.settings.SettingsBuilder;
    +import java.io.File;
    +import java.net.URL;
    +import java.util.HashMap;
    +import java.util.Map;
    +import org.apache.guacamole.GuacamoleException;
    +import org.apache.guacamole.environment.Environment;
    +import org.apache.guacamole.properties.FileGuacamoleProperty;
    +import org.apache.guacamole.properties.StringGuacamoleProperty;
    +import org.apache.guacamole.properties.UrlGuacamoleProperty;
    +
    +/**
    + * 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"; }
    --- End diff --
    
    This is now implemented - OneLogin released version 2.3.0 of their Java SAML client, which includes this capability.


---

[GitHub] guacamole-client pull request #254: GUACAMOLE-103: Implement SAML Authentica...

Posted by necouchman <gi...@git.apache.org>.
Github user necouchman commented on a diff in the pull request:

    https://github.com/apache/guacamole-client/pull/254#discussion_r243860177
  
    --- Diff: extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java ---
    @@ -0,0 +1,202 @@
    +/*
    + * 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;
    +
    +import com.google.inject.Inject;
    +import com.google.inject.Provider;
    +import com.onelogin.saml2.authn.AuthnRequest;
    +import com.onelogin.saml2.authn.SamlResponse;
    +import com.onelogin.saml2.exception.SettingsException;
    +import com.onelogin.saml2.exception.ValidationError;
    +import com.onelogin.saml2.http.HttpRequest;
    +import com.onelogin.saml2.servlet.ServletUtils;
    +import com.onelogin.saml2.settings.Saml2Settings;
    +import com.onelogin.saml2.util.Util;
    +import java.io.IOException;
    +import java.util.Arrays;
    +import javax.servlet.http.HttpServletRequest;
    +import javax.xml.parsers.ParserConfigurationException;
    +import javax.xml.xpath.XPathExpressionException;
    +import org.apache.guacamole.auth.saml.conf.ConfigurationService;
    +import org.apache.guacamole.auth.saml.form.SAMLRedirectField;
    +import org.apache.guacamole.auth.saml.user.AuthenticatedUser;
    +import org.apache.guacamole.GuacamoleException;
    +import org.apache.guacamole.form.Field;
    +import org.apache.guacamole.net.auth.Credentials;
    +import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
    +import org.apache.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException;
    +import org.apache.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException;
    +import org.slf4j.Logger;
    +import org.slf4j.LoggerFactory;
    +import org.xml.sax.SAXException;
    +
    +/**
    + * Class that provides services for use by the SAML Authentication Provider class.
    + */
    +public class AuthenticationProviderService {
    +
    +    /**
    +     * Logger for this class.
    +     */
    +    private final Logger logger = LoggerFactory.getLogger(AuthenticationProviderService.class);
    +
    +    /**
    +     * Service for retrieving SAML configuration information.
    +     */
    +    @Inject
    +    private ConfigurationService confService;
    +
    +    /**
    +     * Provider for AuthenticatedUser objects.
    +     */
    +    @Inject
    +    private Provider<AuthenticatedUser> authenticatedUserProvider;
    +
    +    /**
    +     * Returns an AuthenticatedUser representing the user authenticated by the
    +     * given credentials.
    +     *
    +     * @param credentials
    +     *     The credentials to use for authentication.
    +     *
    +     * @return
    +     *     An AuthenticatedUser representing the user authenticated by the
    +     *     given credentials.
    +     *
    +     * @throws GuacamoleException
    +     *     If an error occurs while authenticating the user, or if access is
    +     *     denied.
    +     */
    +    public AuthenticatedUser authenticateUser(Credentials credentials)
    +            throws GuacamoleException {
    +
    +        HttpServletRequest request = credentials.getRequest();
    +
    +        // Initialize and configure SAML client.
    +        Saml2Settings samlSettings = confService.getSamlSettings();
    +
    +        if (request != null) {
    +            
    +            // Look for the SAML Response parameter.
    +            String samlResponseParam = request.getParameter("SAMLResponse");
    +
    +            if (samlResponseParam != null) {
    +
    +                // Convert the SAML response into the version needed for the client.
    +                HttpRequest httpRequest = ServletUtils.makeHttpRequest(request);
    +                try {
    +
    +                    // Generate the response object
    +                    SamlResponse samlResponse = new SamlResponse(samlSettings, httpRequest);
    +
    +                    if (!samlResponse.validateNumAssertions()) {
    +                        logger.warn("SAML response contained other than single assertion.");
    +                        logger.debug("validateNumAssertions returned false.");
    +                        throw new GuacamoleInvalidCredentialsException("Error during SAML login.",
    +                                CredentialsInfo.USERNAME_PASSWORD);
    +                    }
    +                    if (!samlResponse.validateTimestamps()) {
    +                        logger.warn("SAML response timestamps were invalid.");
    +                        logger.debug("validateTimestamps returned false.");
    +                        throw new GuacamoleInvalidCredentialsException("Error during SAML login.",
    +                                CredentialsInfo.USERNAME_PASSWORD);
    +                    }
    +
    +                    // Grab the username, and, if present, finish authentication.
    +                    String username = samlResponse.getNameId().toLowerCase();
    +                    if (username != null) {
    +                        credentials.setUsername(username);
    +                        AuthenticatedUser authenticatedUser = authenticatedUserProvider.get();
    +                        authenticatedUser.init(username, credentials);
    +                        return authenticatedUser;
    +                    }
    +                }
    +
    +                // Errors are logged and result in a normal username/password login box.
    +                catch (IOException e) {
    +                    logger.warn("Error during I/O while parsing SAML response: {}", e.getMessage());
    +                    logger.debug("Received IOException when trying to parse SAML response.", e);
    +                    throw new GuacamoleInvalidCredentialsException("Error during SAML login.",
    +                                CredentialsInfo.USERNAME_PASSWORD);
    +                }
    +                catch (ParserConfigurationException e) {
    +                    logger.warn("Error configuring XML parser: {}", e.getMessage());
    +                    logger.debug("Received ParserConfigurationException when trying to parse SAML response.", e);
    +                    throw new GuacamoleInvalidCredentialsException("Error during SAML login.",
    +                                CredentialsInfo.USERNAME_PASSWORD);
    +                }
    +                catch (SAXException e) {
    +                    logger.warn("Bad XML when parsing SAML response: {}", e.getMessage());
    +                    logger.debug("Received SAXException while parsing SAML response.", e);
    +                    throw new GuacamoleInvalidCredentialsException("Error during SAML login.",
    +                                CredentialsInfo.USERNAME_PASSWORD);
    +                }
    +                catch (SettingsException e) {
    +                    logger.warn("Error with SAML settings while parsing response: {}", e.getMessage());
    +                    logger.debug("Received SettingsException while parsing SAML response.", e);
    +                    throw new GuacamoleInvalidCredentialsException("Error during SAML login.",
    +                                CredentialsInfo.USERNAME_PASSWORD);
    +                }
    +                catch (ValidationError e) {
    +                    logger.warn("Error validating SAML response: {}", e.getMessage());
    +                    logger.debug("Received ValidationError while parsing SAML response.", e);
    +                    throw new GuacamoleInvalidCredentialsException("Error during SAML login.",
    +                                CredentialsInfo.USERNAME_PASSWORD);
    +                }
    +                catch (XPathExpressionException e) {
    +                    logger.warn("Problem with XML parsing response: {}", e.getMessage());
    +                    logger.debug("Received XPathExpressionException while processing SAML response.", e);
    +                    throw new GuacamoleInvalidCredentialsException("Error during SAML login.",
    +                                CredentialsInfo.USERNAME_PASSWORD);
    +                }
    +                catch (Exception e) {
    +                    logger.warn("Exception while getting name from SAML response: {}", e.getMessage());
    +                    logger.debug("Received Exception while retrieving name from SAML response.", e);
    +                    throw new GuacamoleInvalidCredentialsException("Error during SAML login.",
    +                                CredentialsInfo.USERNAME_PASSWORD);
    +                }
    --- End diff --
    
    Will just keep this as-is for now - better at this point to capture the exceptions with specific error messages than to lump them all together.


---