com.haulmont.idp.controllers.IdpController.java Source code

Java tutorial

Introduction

Here is the source code for com.haulmont.idp.controllers.IdpController.java

Source

/*
 * Copyright (c) 2008-2016 Haulmont.
 *
 * 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.haulmont.idp.controllers;

import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.haulmont.bali.util.URLEncodeUtils;
import com.haulmont.cuba.core.global.ClientType;
import com.haulmont.cuba.core.global.GlobalConfig;
import com.haulmont.cuba.core.global.MessageTools;
import com.haulmont.cuba.core.global.PasswordEncryption;
import com.haulmont.cuba.security.idp.IdpService;
import com.haulmont.cuba.security.global.LoginException;
import com.haulmont.idp.IdpConfig;
import com.haulmont.idp.model.*;
import com.haulmont.idp.sys.IdpServiceLogoutCallbackInvoker;
import org.apache.http.client.utils.URIBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.inject.Inject;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;

/**
 * IDP login form endpoint.
 */
@Controller("cuba_IdpController")
public class IdpController {
    public static final String CUBA_IDP_COOKIE_NAME = "IDP_SESSION_ID";
    public static final String CUBA_IDP_TICKET_PARAMETER = "idp_ticket";

    private static final Logger log = LoggerFactory.getLogger(IdpController.class);

    @Inject
    protected GlobalConfig globalConfig;

    @Inject
    protected IdpConfig idpConfig;

    @Inject
    protected IdpService idpService;

    @Inject
    protected MessageTools messageTools;

    @Inject
    protected PasswordEncryption passwordEncryption;

    @Inject
    protected IdpServiceLogoutCallbackInvoker logoutCallbackInvoker;

    @GetMapping(value = "/")
    public String checkIdpSession(@RequestParam(value = "sp", defaultValue = "") String serviceProviderUrl,
            @RequestParam(value = "response_type", defaultValue = "server-ticket") String responseType,
            @CookieValue(value = CUBA_IDP_COOKIE_NAME, defaultValue = "") String idpSessionCookie,
            HttpServletResponse response) {
        if (!Strings.isNullOrEmpty(serviceProviderUrl)
                && !idpConfig.getServiceProviderUrls().contains(serviceProviderUrl)) {
            log.warn("Incorrect serviceProviderUrl {} passed, will be used default", serviceProviderUrl);
            serviceProviderUrl = null;
        }

        if (Strings.isNullOrEmpty(serviceProviderUrl)) {
            if (!idpConfig.getServiceProviderUrls().isEmpty()) {
                serviceProviderUrl = idpConfig.getServiceProviderUrls().get(0);
            } else {
                log.error("IDP property cuba.idp.serviceProviderUrls is not set");
                response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
                return null;
            }
        }

        if (!Strings.isNullOrEmpty(idpSessionCookie)) {
            String serviceProviderTicket = idpService.createServiceProviderTicket(idpSessionCookie);
            if (serviceProviderTicket != null) {
                String serviceProviderRedirectUrl;
                try {
                    URIBuilder uriBuilder = new URIBuilder(serviceProviderUrl);

                    if (ResponseType.CLIENT_TICKET.getCode().equals(responseType)) {
                        uriBuilder.setFragment(CUBA_IDP_TICKET_PARAMETER + "=" + serviceProviderTicket);
                    } else {
                        uriBuilder.setParameter(CUBA_IDP_TICKET_PARAMETER, serviceProviderTicket);
                    }

                    serviceProviderRedirectUrl = uriBuilder.build().toString();
                } catch (URISyntaxException e) {
                    log.warn("Unable to compose redirect URL", e);

                    response.setStatus(HttpStatus.BAD_REQUEST.value());
                    return null;
                }

                try {
                    response.sendRedirect(serviceProviderRedirectUrl);
                } catch (IOException e) {
                    // do not log stacktrace here
                    log.warn("Unable to send redirect to service provider URL", e.getMessage());
                }

                log.debug("New ticket {} created for already logged in user", serviceProviderTicket);

                return null;
            } else {
                log.debug("IDP session {} not found, login required", idpSessionCookie);
            }
        }

        // remove auth cookie
        Cookie cookie = new Cookie(CUBA_IDP_COOKIE_NAME, "");
        cookie.setMaxAge(0);
        response.addCookie(cookie);

        if (ResponseType.CLIENT_TICKET.getCode().equals(responseType)) {
            return "redirect:login.html" + "?response_type=" + ResponseType.CLIENT_TICKET.getCode() + "&sp="
                    + URLEncodeUtils.encodeUtf8(serviceProviderUrl);
        }

        return "redirect:login.html?sp=" + URLEncodeUtils.encodeUtf8(serviceProviderUrl);
    }

    @GetMapping(value = "/logout")
    public String logout(@RequestParam(value = "sp", defaultValue = "") String serviceProviderUrl,
            @RequestParam(value = "response_type", defaultValue = "server-ticket") String responseType,
            @CookieValue(value = CUBA_IDP_COOKIE_NAME, defaultValue = "") String idpSessionCookie,
            HttpServletResponse response) {
        if (!Strings.isNullOrEmpty(serviceProviderUrl)
                && !idpConfig.getServiceProviderUrls().contains(serviceProviderUrl)) {
            log.warn("Incorrect serviceProviderUrl {} passed, will be used default", serviceProviderUrl);
            serviceProviderUrl = null;
        }

        if (Strings.isNullOrEmpty(serviceProviderUrl)) {
            if (!idpConfig.getServiceProviderUrls().isEmpty()) {
                serviceProviderUrl = idpConfig.getServiceProviderUrls().get(0);
            } else {
                log.error("IDP property cuba.idp.serviceProviderUrls is not set");
                response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
                return null;
            }
        }

        if (!Strings.isNullOrEmpty(idpSessionCookie)) {
            boolean loggedOut = idpService.logout(idpSessionCookie);

            if (loggedOut) {
                log.info("Logged out IDP session {}", idpSessionCookie);

                logoutCallbackInvoker.performLogoutOnServiceProviders(idpSessionCookie);
            }
        }

        // remove auth cookie
        Cookie cookie = new Cookie(CUBA_IDP_COOKIE_NAME, "");
        cookie.setMaxAge(0);
        response.addCookie(cookie);

        if (ResponseType.CLIENT_TICKET.getCode().equals(responseType)) {
            return "redirect:login.html" + "?response_type=" + ResponseType.CLIENT_TICKET.getCode() + "&sp="
                    + URLEncodeUtils.encodeUtf8(serviceProviderUrl);
        }

        return "redirect:login.html?sp=" + URLEncodeUtils.encodeUtf8(serviceProviderUrl);
    }

    @GetMapping(value = "/status", produces = "application/json; charset=UTF-8")
    public ResponseEntity status(
            @CookieValue(value = CUBA_IDP_COOKIE_NAME, defaultValue = "") String idpSessionCookie) {
        if (!Strings.isNullOrEmpty(idpSessionCookie)) {
            String serviceProviderTicket = idpService.createServiceProviderTicket(idpSessionCookie);
            if (serviceProviderTicket != null) {
                return ResponseEntity.ok(new IdpTicket(serviceProviderTicket));
            }
        }

        return ResponseEntity.noContent().build();
    }

    @PostMapping(value = "/auth", produces = "application/json; charset=UTF-8")
    @ResponseBody
    public AuthResponse authenticate(@RequestBody AuthRequest auth,
            @CookieValue(value = CUBA_IDP_COOKIE_NAME, defaultValue = "") String idpSessionCookie,
            HttpServletResponse response) {
        String serviceProviderUrl = auth.getServiceProviderUrl();

        if (!Strings.isNullOrEmpty(serviceProviderUrl)
                && !idpConfig.getServiceProviderUrls().contains(serviceProviderUrl)) {
            log.warn("Incorrect serviceProviderUrl {} passed, will be used default", serviceProviderUrl);
            serviceProviderUrl = null;
        }

        if (Strings.isNullOrEmpty(serviceProviderUrl)) {
            if (!idpConfig.getServiceProviderUrls().isEmpty()) {
                serviceProviderUrl = idpConfig.getServiceProviderUrls().get(0);
            } else {
                log.error("IDP property cuba.idp.serviceProviderUrls is not set");
                response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
                return null;
            }
        }

        Locale sessionLocale = null;
        if (globalConfig.getLocaleSelectVisible() && auth.getLocale() != null) {
            Map<String, Locale> availableLocales = globalConfig.getAvailableLocales();
            Locale requestedLocale = Locale.forLanguageTag(auth.getLocale());

            if (availableLocales.containsValue(requestedLocale)) {
                sessionLocale = requestedLocale;
            }
        }
        if (sessionLocale == null) {
            sessionLocale = messageTools.getDefaultLocale();
        }

        if (!Strings.isNullOrEmpty(idpSessionCookie)) {
            boolean loggedOut = idpService.logout(idpSessionCookie);

            if (loggedOut) {
                log.info("Logged out IDP session {}", idpSessionCookie);

                logoutCallbackInvoker.performLogoutOnServiceProviders(idpSessionCookie);
            }
        }

        IdpService.IdpLoginResult loginResult;
        try {
            loginResult = idpService.login(auth.getUsername(), passwordEncryption.getPlainHash(auth.getPassword()),
                    sessionLocale, ImmutableMap.of(ClientType.class.getName(), ClientType.WEB.name()));
        } catch (LoginException e) {
            // remove auth cookie
            Cookie cookie = new Cookie(CUBA_IDP_COOKIE_NAME, "");
            cookie.setMaxAge(0);
            response.addCookie(cookie);

            log.warn("Unable to login user {}", auth.getUsername());
            return AuthResponse.failed("invalid_credentials");
        }

        if (loginResult.getSessionId() != null) {
            Cookie idpCookie = new Cookie(CUBA_IDP_COOKIE_NAME, loginResult.getSessionId());
            idpCookie.setMaxAge(idpConfig.getIdpCookieMaxAge());
            idpCookie.setHttpOnly(idpConfig.getIdpCookieHttpOnly());
            response.addCookie(idpCookie);
        }

        String serviceProviderRedirectUrl;
        try {
            URIBuilder uriBuilder = new URIBuilder(serviceProviderUrl);

            if ("client-ticket".equals(auth.getResponseType())) {
                uriBuilder.setFragment(CUBA_IDP_TICKET_PARAMETER + "=" + loginResult.getServiceProviderTicket());
            } else {
                uriBuilder.setParameter(CUBA_IDP_TICKET_PARAMETER, loginResult.getServiceProviderTicket());
            }

            serviceProviderRedirectUrl = uriBuilder.build().toString();
        } catch (URISyntaxException e) {
            return AuthResponse.failed("invalid_params");
        }

        log.info("Logged in IDP session with ticket {}, user: {}", loginResult.getServiceProviderTicket(),
                auth.getUsername());

        return AuthResponse.authenticated(serviceProviderRedirectUrl);
    }

    @GetMapping(value = "/locales", produces = "application/json; charset=UTF-8")
    @ResponseBody
    public LocalesInfo getLocales() {
        LocalesInfo localesInfo = new LocalesInfo();

        localesInfo.setLocaleSelectVisible(globalConfig.getLocaleSelectVisible());

        Map<String, String> locales = new LinkedHashMap<>();
        for (Map.Entry<String, Locale> entry : globalConfig.getAvailableLocales().entrySet()) {
            locales.put(entry.getValue().toLanguageTag(), entry.getKey());
        }
        localesInfo.setLocales(locales);

        return localesInfo;
    }
}