jp.opencollector.guacamole.auth.delegated.DelegatedAuthenticationProvider.java Source code

Java tutorial

Introduction

Here is the source code for jp.opencollector.guacamole.auth.delegated.DelegatedAuthenticationProvider.java

Source

// Copyright (c) 2015 Open Collector, Inc.
// Copyright (c) 2015 Moriyoshi Koizumi
// 
// 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.

package jp.opencollector.guacamole.auth.delegated;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;

import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
import org.glyptodon.guacamole.net.auth.Credentials;
import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.core.io.IOContext;
import com.fasterxml.jackson.core.json.ReaderBasedJsonParser;
import com.fasterxml.jackson.core.json.UTF8StreamJsonParser;
import com.fasterxml.jackson.core.util.BufferRecycler;
import com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer;
import com.fasterxml.jackson.core.sym.CharsToNameCanonicalizer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import com.google.common.base.Optional;
import com.google.common.net.MediaType;

public class DelegatedAuthenticationProvider implements AuthenticationProvider {
    private static final Charset UTF_8 = Charset.forName("UTF-8");
    private static final ByteQuadsCanonicalizer byteSymbolCanonicalizer = ByteQuadsCanonicalizer.createRoot();
    private static final CharsToNameCanonicalizer symbolCanonicalizer = CharsToNameCanonicalizer.createRoot();

    public String getIdentifier() {
        return "delegated";
    }

    public org.glyptodon.guacamole.net.auth.AuthenticatedUser authenticateUser(Credentials credentials)
            throws GuacamoleException {
        final Optional<GuacamoleConfiguration> config = buildConfigurationFromRequest(credentials.getRequest());
        if (!config.isPresent())
            return null;
        return new AuthenticatedUser(this, "delegated", credentials, config.get());
    }

    public org.glyptodon.guacamole.net.auth.AuthenticatedUser updateAuthenticatedUser(
            org.glyptodon.guacamole.net.auth.AuthenticatedUser authenticatedUser, Credentials credentials)
            throws GuacamoleException {
        return authenticatedUser;
    }

    public org.glyptodon.guacamole.net.auth.UserContext getUserContext(
            org.glyptodon.guacamole.net.auth.AuthenticatedUser authenticatedUser) throws GuacamoleException {
        return new UserContext(this, "delegated", (AuthenticatedUser) authenticatedUser);
    }

    public org.glyptodon.guacamole.net.auth.UserContext updateUserContext(
            org.glyptodon.guacamole.net.auth.UserContext context,
            org.glyptodon.guacamole.net.auth.AuthenticatedUser authenticatedUser) throws GuacamoleException {
        return context;
    }

    private static JsonParser createJsonParser(InputStream is, Charset charset, ObjectCodec codec) {
        final IOContext ctxt = new IOContext(new BufferRecycler(), is, false);
        if (charset.equals(UTF_8)) {
            final byte[] buf = ctxt.allocReadIOBuffer();
            return new UTF8StreamJsonParser(ctxt, 0, is, codec,
                    byteSymbolCanonicalizer.makeChild(JsonFactory.Feature.CANONICALIZE_FIELD_NAMES.getMask()), buf,
                    0, 0, true);
        } else {
            return new ReaderBasedJsonParser(ctxt, 0, new InputStreamReader(is, charset), codec,
                    symbolCanonicalizer.makeChild(JsonFactory.Feature.CANONICALIZE_FIELD_NAMES.getMask()));
        }
    }

    private static Optional<GuacamoleConfiguration> buildConfigurationFromRequest(HttpServletRequest req)
            throws GuacamoleException {
        try {
            if (req.getClass().getName().equals("org.glyptodon.guacamole.net.basic.rest.APIRequest")) {
                final GuacamoleConfiguration config = new GuacamoleConfiguration();
                final String protocol = req.getParameter("protocol");
                if (protocol == null)
                    throw new GuacamoleException("required parameter \"protocol\" is missing");
                config.setProtocol(protocol);
                for (Map.Entry<String, String[]> param : req.getParameterMap().entrySet()) {
                    String[] values = param.getValue();
                    if (values.length > 0)
                        config.setParameter(param.getKey(), values[0]);
                }
                return Optional.of(config);
            } else {
                final ServletInputStream is = req.getInputStream();
                if (!is.isReady()) {
                    MediaType contentType = MediaType.parse(req.getContentType());
                    boolean invalidContentType = true;
                    if (contentType.type().equals("application")) {
                        if (contentType.subtype().equals("json")) {
                            invalidContentType = false;
                        } else if (contentType.subtype().equals("x-www-form-urlencoded")
                                && req.getParameter("token") != null) {
                            return Optional.<GuacamoleConfiguration>absent();
                        }
                    }
                    if (invalidContentType)
                        throw new GuacamoleException(String.format("expecting application/json, got %s",
                                contentType.withoutParameters()));
                    final GuacamoleConfiguration config = new GuacamoleConfiguration();
                    try {
                        final ObjectMapper mapper = new ObjectMapper();
                        JsonNode root = (JsonNode) mapper.readTree(
                                createJsonParser(req.getInputStream(), contentType.charset().or(UTF_8), mapper));
                        {
                            final JsonNode protocol = root.get("protocol");
                            if (protocol == null)
                                throw new GuacamoleException("required parameter \"protocol\" is missing");
                            final JsonNode parameters = root.get("parameters");
                            if (parameters == null)
                                throw new GuacamoleException("required parameter \"parameters\" is missing");
                            config.setProtocol(protocol.asText());
                            {
                                for (Iterator<Entry<String, JsonNode>> i = parameters.fields(); i.hasNext();) {
                                    Entry<String, JsonNode> member = i.next();
                                    config.setParameter(member.getKey(), member.getValue().asText());
                                }
                            }
                        }
                    } catch (ClassCastException e) {
                        throw new GuacamoleException("error occurred during parsing configuration", e);
                    }
                    return Optional.of(config);
                } else {
                    return Optional.<GuacamoleConfiguration>absent();
                }
            }
        } catch (IOException e) {
            throw new GuacamoleException("error occurred during retrieving configuration from the request body", e);
        }
    }

    public DelegatedAuthenticationProvider() throws GuacamoleException {
    }
}