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.


---

Reply via email to