Coder Social home page Coder Social logo

cuba-platform / saml-addon Goto Github PK

View Code? Open in Web Editor NEW
4.0 8.0 2.0 476 KB

This component provides a readily available instrument of authentication in any CUBA-based application using SAML open standard. That allows identity provider to pass authorization credentials to your applications - service providers.

License: Apache License 2.0

Java 100.00%
cuba-platform cuba-component apache2 saml

saml-addon's Introduction

license Build Status

SAML

1. Overview

This component provides a readily available instrument of authentication in any CUBA-based application using SAML open standard. That allows identity provider (IdP) to pass authorization credentials to your applications - service providers (SP).

The add-on enables Single Sign-On in your application. You log in once with the IdP and this set of credentials will be used to log in your CUBA applications.

Key features:

  • simplified authorization procedure for users and service providers;
  • separately existing of an identity provider and service providers, which centralizes user management;
  • user interface to set and configure SAML connections.

See sample project using this add-on.

2. Installation

The add-on can be added to your project in one of the ways described below. Installation from the Marketplace is the simplest way. The last version of the add-on compatible with the used version of the platform will be installed. Also, you can install the add-on by coordinates choosing the required version of the add-on from the table.

In case you want to install the add-on by manual editing or by building from sources see the complete add-ons installation guide in CUBA Platform documentation.

2.1. From the Marketplace

  1. Open your application in CUBA Studio. Check the latest version of CUBA Studio on the CUBA Platform site.
  2. Go to CUBA -> Marketplace in the main menu.

marketplace

  1. Find the SAML add-on there.

addons

  1. Click Install and apply the changes. The add-on corresponding to the used platform version will be installed.

2.2. By coordinates

  1. Open your application in CUBA Studio. Check the latest version of CUBA Studio on the CUBA Platform site.
  2. Go to CUBA -> Marketplace in the main menu.
  3. Click the icon in the upper-right corner.

by-coordinates

  1. Paste the add-on coordinates in the corresponding field as follows:

com.haulmont.addon.saml:saml-addon-global:<add-on version>

where <add-on version> is compatible with the used version of the CUBA platform.

Platform Version Add-on Version
7.2.x 0.4.1
7.1.x 0.3.0
7.0.x 0.2.2
6.10.x 0.1.0
  1. Click Install and apply the changes. The add-on will be installed to your project.

3. Configuration

To use your own key for keystore passwords encryption specify encryption.key and encryption.iv properties in app.properties.xml in the core module. Otherwise, the default keys declared in the app-component.xml file will be used.

The further configuration consists of creating keystore and setting SAML connection.

3.1. Keystore

Before setting SAML connection you need to create keystore containing a username, password, description, and JKS (Java Key Store) file. Your service provider application must have a unique public/private key pair.

3.1.1 Creating keystore

Firstly, you need to generate a public/private key pair. Use the following links to instructions:

You will get JKS file as the result.

Create a keystore using your application UI:

  1. Go to Administration -> SAML screen.
  2. Click the KeyStore button.
  3. Click the Create button.
  4. Fill in the Login field - login that was used for JKS file generation.
  5. Fill in the Password field - password that was used for JKS file generation.
  6. (Optional) Fill in the Description field - will be used with the login as keystore representation in SAML Connection editor screen.
  7. Upload .jks keystore file.
  8. Click OK to create the keystore with entered settings.

You can not delete keystore if it is linked at least to one connection. Firstly, you need to unselect keystore in SAML Connection editor screen.

3.2 SAML Connection

To configure SAML connection to identity provider do the following steps:

  1. Go to Administration -> SAML screen.
  2. Click the Create button.
  3. Fill in the Name field - it will be shown to users in the login screen.
  4. Fill in the SSO Path field - it will be used for tenant login.
  5. Select the required keystore in the drop-down list of Keystore field.
  6. Choose Default access group that will be set to new users logged in with this IdP.
  7. Choose Processing service to process new users logged in with this IdP.
  8. Fill in the Service provider identity. This field will be used by IdP to identify your application. For example: cuba-saml-demo. Then click the Refresh button. Copy the generated XML from the field below and register it in the IdP.
  9. Fill in the Identity Provider metadata URL field provided by this IdP. Example: http://idp.ssocircle.com/idp-meta.xml. Then click the Refresh button. If the URL is correct and IdP works OK - you will see some XML content below. Another way to specify IdP metadata is to upload an XML file using the corresponding button.
  10. Click User Creation checkbox, if you want to create a user from information received from IdP in case the user does not exist in the application.
  11. Click Active checkbox. After that, the IdP will be shown in the login screen.
  12. Click OK to save settings.

3.3 Tenant Logging

Using a specific tenant URL is a simple way to log in. For example, http://localhost:8080/app/saml/login?tenant=ssoPath, where ssoPath is the value of the field with the same name in SAML Connection entity. When you use such URL, the system automatically redirects you to the specific IdP.

3.4 SAML Processor

By default, the component provides BaseSamlProcessor which fills in the following attributes for the new user from the SAML session:

  • FirstName
  • LastName
  • MiddleName
  • EmailAddress

However, you can define your own implementation of the interface com.haulmont.addon.saml.core.SamlProcessor which will handle the SAML data using your own logic. The getName() method should return a user-friendly name, to show it in the lookup field on the SAML Connection editor screen.

3.5. Predefined roles

  • saml-admin - grants full access to SAML configuration.

4. Implementation

4.1. Extension of the Standard Login Window

To extend the standard login screen:

  1. Open your project in CUBA Studio.
  2. Expand the Generic UI in the CUBA project tree.
  3. Right-click Screens and go to New -> Screen.
  4. Go to the Legacy Screen Templates tab and select the Login window.
  5. Click Next -> Finish.

Then add a lookup field with the list of IdP providers in the screen controller. When you choose one of providers SAML request will be initiated.

Here is an example of the implementation of the whole controller:

  1. Screen controller ext-loginWindow.xml:
Click to expand the code
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
        class="com.haulmont.sd.web.screens.ExtAppLoginWindow"
        extends="/com/haulmont/cuba/web/app/loginwindow/loginwindow.xml"
        xmlns:ext="http://schemas.haulmont.com/cuba/window-ext.xsd"
        messagesPack="com.haulmont.sd.web.screens">
    <dialogMode height="600"
                width="800"/>
    <layout>
        <vbox id="loginWrapper">
            <vbox id="loginMainBox">
                <grid id="loginFormLayout">
                    <columns>
                        <column id="loginFormCaptionColumn"/>
                        <column id="loginFormFieldColumn"/>
                    </columns>
                    <rows>
                        <row id="ssoRow" ext:index="0">
                            <label id="ssoLookupFieldLabel" value="msg://captions.loginBy" align="MIDDLE_CENTER"/>
                            <lookupField id="ssoLookupField" nullOptionVisible="true" align="MIDDLE_CENTER"/>
                        </row>
                    </rows>
                </grid>
            </vbox>
        </vbox>
    </layout>
</window>
  1. Java class ExtAppLoginWindow.java
Click to expand the example for 6.10
import com.haulmont.addon.saml.entity.SamlConnection;
import com.haulmont.addon.saml.security.SamlSession;
import com.haulmont.addon.saml.security.config.SamlConfig;
import com.haulmont.addon.saml.service.SamlService;
import com.haulmont.addon.saml.web.security.saml.SamlSessionPrincipal;
import com.haulmont.cuba.core.global.DataManager;
import com.haulmont.cuba.core.global.LoadContext;
import com.haulmont.cuba.core.global.View;
import com.haulmont.cuba.core.sys.AppContext;
import com.haulmont.cuba.core.sys.SecurityContext;
import com.haulmont.cuba.gui.components.Label;
import com.haulmont.cuba.gui.components.LookupField;
import com.haulmont.cuba.gui.executors.BackgroundWorker;
import com.haulmont.cuba.gui.executors.UIAccessor;
import com.haulmont.cuba.security.app.TrustedClientService;
import com.haulmont.cuba.security.auth.Credentials;
import com.haulmont.cuba.security.entity.User;
import com.haulmont.cuba.security.global.LoginException;
import com.haulmont.cuba.security.global.UserSession;
import com.haulmont.cuba.web.app.loginwindow.AppLoginWindow;
import com.haulmont.cuba.web.auth.WebAuthConfig;
import com.haulmont.cuba.web.security.ExternalUserCredentials;
import com.vaadin.server.*;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nullable;
import javax.inject.Inject;
import java.io.IOException;
import java.security.Principal;
import java.util.Collections;
import java.util.List;
import java.util.Map;

public class ExtAppLoginWindow extends AppLoginWindow {

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

    @Inject
    protected SamlService samlService;
    @Inject
    protected TrustedClientService trustedClientService;
    @Inject
    protected DataManager dataManager;
    @Inject
    protected BackgroundWorker backgroundWorker;

    @Inject
    protected SamlConfig samlConfig;
    @Inject
    protected WebAuthConfig webAuthConfig;

    @Inject
    protected Label ssoLookupFieldLabel;
    @Inject
    protected LookupField ssoLookupField;

    protected RequestHandler samlCallbackRequestHandler = this::handleSamlCallBackRequest;

    protected UIAccessor uiAccessor;

    @Override
    public void init(Map<String, Object> params) {
        super.init(params);

        uiAccessor = backgroundWorker.getUIAccessor();

        ssoLookupField.setOptionsList(getActiveConnections());
        ssoLookupFieldLabel.setVisible(!CollectionUtils.isEmpty(ssoLookupField.getOptionsList()));
        ssoLookupField.setVisible(!CollectionUtils.isEmpty(ssoLookupField.getOptionsList()));
        ssoLookupField.addValueChangeListener(e -> {
            if (e.getValue() != null) {
                SamlConnection connection = (SamlConnection) e.getValue();
                VaadinSession.getCurrent().getSession().setAttribute(SamlSessionPrincipal.SAML_CONNECTION_CODE, connection.getCode());
                Page.getCurrent().setLocation(getLoginUrl());
            }
            ssoLookupField.setValue(null);
        });
    }

    @Override
    public void ready() {
        super.ready();

        VaadinSession.getCurrent().addRequestHandler(samlCallbackRequestHandler);
        try {
            samlCallbackRequestHandler.handleRequest(VaadinSession.getCurrent(), null, null);
        } catch (IOException e) {
            log.error("Failed to check SAML login", e);
        }
    }

    protected boolean handleSamlCallBackRequest(VaadinSession session, @Nullable VaadinRequest request,
                                                @Nullable VaadinResponse response) throws IOException {
        Principal principal = VaadinService.getCurrentRequest().getUserPrincipal();
        if (principal instanceof SamlSessionPrincipal) {
            SamlSessionPrincipal samlPrincipal = (SamlSessionPrincipal) principal;
            if (samlPrincipal.isActive()) {
                final SamlSession samlSession = samlPrincipal.getSamlSession();
                uiAccessor.accessSynchronously(() -> {
                    try {
                        User user = samlService.getUser(samlSession);
                        ExternalUserCredentials credentials = new ExternalUserCredentials(user.getLogin());
                        doLogin(credentials);
                    } catch (LoginException e) {
                        log.info("Login by SAML failed", e);

                        showLoginException(String.format(getMessage("errors.message.samlLoginFailed"), samlSession.getPrincipal()));
                    } catch (Exception e) {
                        log.warn("Login by SAML failed. Internal error.", e);

                        showUnhandledExceptionOnLogin(e);
                    }
                });
            }
        }
        return false;
    }

    @Override
    protected void doLogin(Credentials credentials) throws LoginException {
        super.doLogin(credentials);

        VaadinSession.getCurrent().removeRequestHandler(samlCallbackRequestHandler);
    }

    protected List<SamlConnection> getActiveConnections() {
        UserSession systemSession;
        try {
            systemSession = trustedClientService.getSystemSession(webAuthConfig.getTrustedClientPassword());
        } catch (LoginException e) {
            log.error("Unable to obtain system session", e);
            return Collections.emptyList();
        }
        return AppContext.withSecurityContext(new SecurityContext(systemSession), () -> {
            List<SamlConnection> items = dataManager.loadList(LoadContext.create(SamlConnection.class)
                    .setQuery(new LoadContext.Query("select e from samladdon$SamlConnection e where e.active = true order by e.code"))
                    .setView(View.MINIMAL));
            return items;
        });
    }

    protected String getLoginUrl() {
        return (samlConfig.getProxyEnabled() ? samlConfig.getProxyServerUrl() : globalConfig.getWebAppUrl())
                 + samlConfig.getSamlBasePath() + samlConfig.getSamlLoginPath();
    }
}
Click to expand the example for 7.0
import com.haulmont.addon.saml.entity.SamlConnection;
import com.haulmont.addon.saml.security.SamlSession;
import com.haulmont.addon.saml.security.config.SamlConfig;
import com.haulmont.addon.saml.service.SamlService;
import com.haulmont.addon.saml.web.security.saml.SamlSessionPrincipal;
import com.haulmont.cuba.core.global.DataManager;
import com.haulmont.cuba.core.global.LoadContext;
import com.haulmont.cuba.core.global.View;
import com.haulmont.cuba.core.sys.AppContext;
import com.haulmont.cuba.core.sys.SecurityContext;
import com.haulmont.cuba.gui.components.Label;
import com.haulmont.cuba.gui.components.LookupField;
import com.haulmont.cuba.gui.executors.BackgroundWorker;
import com.haulmont.cuba.gui.executors.UIAccessor;
import com.haulmont.cuba.security.app.TrustedClientService;
import com.haulmont.cuba.security.auth.Credentials;
import com.haulmont.cuba.security.entity.User;
import com.haulmont.cuba.security.global.LoginException;
import com.haulmont.cuba.security.global.UserSession;
import com.haulmont.cuba.web.app.loginwindow.AppLoginWindow;
import com.haulmont.cuba.web.auth.WebAuthConfig;
import com.haulmont.cuba.web.security.ExternalUserCredentials;
import com.vaadin.server.*;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nullable;
import javax.inject.Inject;
import java.io.IOException;
import java.security.Principal;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import static java.util.Objects.isNull;

public class ExtAppLoginWindow extends AppLoginWindow {

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

    @Inject
    protected SamlService samlService;
    @Inject
    protected TrustedClientService trustedClientService;
    @Inject
    protected DataManager dataManager;
    @Inject
    protected BackgroundWorker backgroundWorker;

    @Inject
    protected SamlConfig samlConfig;
    @Inject
    protected WebAuthConfig webAuthConfig;

    @Inject
    protected Label<String> ssoLookupFieldLabel;
    @Inject
    protected LookupField<SamlConnection> ssoLookupField;

    protected RequestHandler samlCallbackRequestHandler = this::handleSamlCallBackRequest;

    protected UIAccessor uiAccessor;

    @Override
    public void init(Map<String, Object> params) {
        super.init(params);

        uiAccessor = backgroundWorker.getUIAccessor();

        ssoLookupField.setOptionsList(getActiveConnections());
        ssoLookupFieldLabel.setVisible(!CollectionUtils.isEmpty(ssoLookupField.getOptionsList()));
        ssoLookupField.setVisible(!CollectionUtils.isEmpty(ssoLookupField.getOptionsList()));
        ssoLookupField.addValueChangeListener(e -> {
            if (e.getValue() != null) {
                SamlConnection connection = e.getValue();
                VaadinSession.getCurrent().getSession().setAttribute(SamlSessionPrincipal.SAML_CONNECTION_CODE, connection.getSsoPath());
                Page.getCurrent().setLocation(getLoginUrl());
            }
            ssoLookupField.setValue(null);
        });
    }

    @Override
    public void ready() {
        super.ready();

        VaadinSession.getCurrent().addRequestHandler(samlCallbackRequestHandler);
        try {
            samlCallbackRequestHandler.handleRequest(VaadinSession.getCurrent(), null, null);
        } catch (IOException e) {
            log.error("Failed to check SAML login", e);
        }
    }

    protected boolean handleSamlCallBackRequest(VaadinSession session, @Nullable VaadinRequest request,
                                                @Nullable VaadinResponse response) throws IOException {
        Principal principal = VaadinService.getCurrentRequest().getUserPrincipal();
        if (principal instanceof SamlSessionPrincipal) {
            SamlSessionPrincipal samlPrincipal = (SamlSessionPrincipal) principal;
            if (samlPrincipal.isActive()) {
                final SamlSession samlSession = samlPrincipal.getSamlSession();
                uiAccessor.accessSynchronously(() -> {
                    try {
                        User user = samlService.getUser(samlSession);
                        if (isNull(user)) {
                            throw new LoginException("User does not exists");
                        }
                        ExternalUserCredentials credentials = new ExternalUserCredentials(user.getLogin());
                        doLogin(credentials);
                    } catch (LoginException e) {
                        log.info("Login by SAML failed", e);

                        showLoginException(String.format(getMessage("errors.message.samlLoginFailed"), samlSession.getPrincipal()));
                    } catch (Exception e) {
                        log.warn("Login by SAML failed. Internal error.", e);

                        showUnhandledExceptionOnLogin(e);
                    }
                });
            }
        }
        //check the error
        Object error = VaadinService.getCurrentRequest().getWrappedSession()
                .getAttribute(SamlSessionPrincipal.SAML_ERROR_ATTRIBUTE);
        if (error != null) {
            uiAccessor.accessSynchronously(() -> {
                showUnhandledExceptionOnLogin((Exception) error);
            });
        }
        return false;
    }

    @Override
    protected void doLogin(Credentials credentials) throws LoginException {
        super.doLogin(credentials);

        VaadinSession.getCurrent().removeRequestHandler(samlCallbackRequestHandler);
    }

    protected List<SamlConnection> getActiveConnections() {
        UserSession systemSession;
        try {
            systemSession = trustedClientService.getSystemSession(webAuthConfig.getTrustedClientPassword());
        } catch (LoginException e) {
            log.error("Unable to obtain system session", e);
            return Collections.emptyList();
        }
        return AppContext.withSecurityContext(new SecurityContext(systemSession), () -> {
            List<SamlConnection> items = dataManager.loadList(LoadContext.create(SamlConnection.class)
                    .setQuery(new LoadContext.Query("select e from samladdon$SamlConnection e where e.active = true order by e.ssoPath"))
                    .setView(View.MINIMAL));
            return items;
        });
    }

    protected String getLoginUrl() {
        return (samlConfig.getProxyEnabled() ? samlConfig.getProxyServerUrl() : globalConfig.getWebAppUrl())
                + samlConfig.getSamlBasePath() + samlConfig.getSamlLoginPath();
    }
}
  1. The messages.properties file should contain the following strings:
captions.loginBy = Login by
errors.message.samlLoginFailed = User '%s' hasn't been logged by SAML.
  1. The web-app.properties file should contain the following strings:
cuba.addon.saml.basePath = /saml
cuba.addon.saml.logoutPath = /logout
cuba.addon.saml.loginPath = /login
cuba.addon.saml.metadataPath = /metadata
cuba.addon.saml.responseSkewSec = 60
cuba.addon.saml.maxAuthenticationAgeSec = 7200
cuba.addon.saml.maxAssertionTimeSec = 3000
cuba.addon.saml.logAllSamlMessages = true

Also, you can observe the details of the implementation in the corresponding demo project.

4.2. Setup signing method for SAML messages

By default, OpenSAML component uses SHA1 digest algorithm for signing SAML messages. The most convenient way to use different signing messages is to create a class in the web module with additional changes in SecurityContext.

Click to expand the example
import org.opensaml.xml.Configuration;
import org.opensaml.xml.security.BasicSecurityConfiguration;
import org.opensaml.xml.signature.SignatureConstants;

public class SecurityConfiguration {

 public void initialize() {
        BasicSecurityConfiguration configuration = (BasicSecurityConfiguration) Configuration.getGlobalSecurityConfiguration();

        // Asymmetric key algorithms
        configuration.registerSignatureAlgorithmURI("RSA", SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256);
        configuration.registerSignatureAlgorithmURI("DSA", SignatureConstants.ALGO_ID_SIGNATURE_DSA);
        configuration.registerSignatureAlgorithmURI("EC", SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA256);

        // HMAC algorithms
        configuration.registerSignatureAlgorithmURI("AES", SignatureConstants.ALGO_ID_MAC_HMAC_SHA256);
        configuration.registerSignatureAlgorithmURI("DESede", SignatureConstants.ALGO_ID_MAC_HMAC_SHA256);

        // Other signature-related params
        configuration.setSignatureCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
        configuration.setSignatureHMACOutputLength(null);
        configuration.setSignatureReferenceDigestMethod(SignatureConstants.ALGO_ID_DIGEST_SHA256);
    }
}

Create a file in the web module for additional configuration of SAML servlet and declare the SecurityConfiguration class as a bean. For example, you can name this file as saml-dispatcher-spring.xml.

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">

    <bean class="com.haulmont.demo.saml.web.SecurityConfiguration" init-method="initialize" depends-on="samlBootstrap"/>

</beans>

Basic configuration is initialized in the org.springframework.security.saml.SAMLBootstrap class. To make sure that security config is initialized and does not override your changes set depends-on attribute with the value of the bean id of the org.springframework.security.saml.SAMLBootstrap class (related bean is declared in the saml-dispatcher-spring.xml file of the addon).

Then add the saml.springContextConfig property to the web-app.properties file and set the value with the path of your additional configuration file. (The plus sign is necessary, see documentation).

saml.springContextConfig = +com/haulmont/demo/saml/saml-dispatcher-spring.xml

Pay attention that the signing method declared in your configuration will be used for all created SAML connections! All supported signing methods are declared in the org.opensaml.xml.signature.SignatureConstants class.

5. General Application Properties

cuba.addon.saml.basePath

  • Description: URL SAML context path, e.g. /saml
  • Interface: SamlConfig
    Used in the Web Client.

cuba.addon.saml.loginPath

  • Description: SAML login path part, e.g. /login, and with the base path the result will be /saml/logout
  • Interface: SamlConfig
    Used in the Web Client.

cuba.addon.saml.logoutPath

  • Description: SAML logout path part, e.g. /logout and with the base path the result will be /saml/logout
  • Interface: SamlConfig
    Used in the Web Client.

cuba.addon.saml.metadataPath

  • Description: SAML metadata display path part, e.g. /metadata and with the base path the result will be /saml/metadata?tenant=code where code is SAMLConnection.code
  • Interface: SamlConfig
    Used in the Web Client.

cuba.addon.saml.responseSkewSec

  • Description: Maximum difference between local time and time of the assertion creation which still allows message to be processed. Basically determines maximum difference between clocks of the IdP and SP machines (in seconds).
  • Default value: 60
  • Interface: SamlConfig
    Used in the Web Client.

cuba.addon.saml.maxAuthenticationAgeSec

  • Description: Maximum time between users authentication and processing of the AuthNResponse message (in seconds).
  • Default value: 7200
  • Interface: SamlConfig
    Used in the Web Client.

cuba.addon.saml.maxAssertionTimeSec

  • Description: Maximum time between assertion creation and current time when the assertion is usable (in seconds).
  • Default value: 3000
  • Interface: SamlConfig
    Used in the Web Client.

cuba.addon.saml.ssoLogout

  • Description: Defines whether the logout action will be also performed on the IdP when user performs logout in the CUBA application (SP)
  • Default value: false
  • Interface: SamlConfig
    Used in the Web Client.

cuba.addon.saml.proxy.enabled

  • Description: Defines is a application use a proxy server or not
  • Default value: false
  • Interface: SamlConfig
    Used in the Web Client.

cuba.addon.saml.proxy.serverUrl

  • Description: Defines the address of remote proxy server if a proxy server is using, e.g. https://myhost.com
  • Default value: **
  • Interface: SamlConfig
    Used in the Web Client.

cuba.addon.saml.logAllSamlMessages

  • Description: Determines if all SAML messages should be logged
  • Default value: true
  • Interface: SamlConfig
    Used in the Web Client.

saml-addon's People

Contributors

bujoralexandru avatar gecrepo avatar glebshalyganov avatar gorbunkov avatar mikhailstrokov avatar tinhol avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

saml-addon's Issues

Create predefined roles

Environment

  • Platform version: 7.2.x
  • Addon version: 0.4-SNAPSHOT

Description

Create predefined system roles

Check trust identity working incorrectly

Environment

  • Platform version: 6.8.10
  • Addon version: 0.1-SNAPSHOT

Description of the bug or enhancement

When a new SAML connection is created that authenticates with a Microsoft ADFS server, this typically fails on the first attempt.

PKIX path construction failed for untrusted credential: [subjectName='CN=ADFS Signing - host']: unable to find valid certification path to requested target

ERROR o.o.s.m.p.SignatureValidationFilter - Signature trust establishment failed for metadata entry http://host/adfs/services/trust

Update scripts for MSSQL and Oracle are invalid

Environment

  • Platform version: 7.2.x
  • Addon version: 0.5.0

Description of the bug or enhancement

Update scripts for MSSQL and Oracle databases are invalid.

Test case

  • Run sample project with SAML 0.4.0 and MSSQL/Oracle db
  • Upgrade SAML to 0.5.0
  • Update database

ER: db updated successfully
AR: Error executing SQL script 201022-2-updateKeyStore.sql

Wrong AssertionConsumerService URL

Environment

  • Platform version: 7.2.5
  • Addon version: 0.5.2

Description of the bug or enhancement

The problem is that generated SP metadata has AssertionConsumerService wrong url. It generates IDP url, not SP.
Looking at the code it shoud be webAppUrl or ProxyUrl. But it's not. IDP url only provided in IDP-metadata and SSO PATH.

Application start fails in case both REST API and SAML add-on are included

Environment

  • Platform version: 7.2.20
  • SAML add-on version: 0.5.2
  • REST API add-on version: 7.2.5

Description of the bug or enhancement

Application fails in start with the following exception:

org.xml.sax.SAXParseException: schema_reference.4: Failed to read schema document 'http://www.springframework.org/schema/security/spring-security.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
	at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source) ~[xercesImpl-2.12.0.jar:na]
	at org.apache.xerces.util.ErrorHandlerWrapper.warning(Unknown Source) ~[xercesImpl-2.12.0.jar:na]
	at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source) ~[xercesImpl-2.12.0.jar:2.12.0]
	at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source) ~[xercesImpl-2.12.0.jar:2.12.0]
	at org.apache.xerces.impl.xs.traversers.XSDHandler.reportSchemaWarning(Unknown Source) ~[xercesImpl-2.12.0.jar:na]
	at org.apache.xerces.impl.xs.traversers.XSDHandler.getSchemaDocument1(Unknown Source) ~[xercesImpl-2.12.0.jar:na]
	at org.apache.xerces.impl.xs.traversers.XSDHandler.getSchemaDocument(Unknown Source) ~[xercesImpl-2.12.0.jar:na]
	at org.apache.xerces.impl.xs.traversers.XSDHandler.parseSchema(Unknown Source) ~[xercesImpl-2.12.0.jar:na]
	at org.apache.xerces.impl.xs.XMLSchemaLoader.loadSchema(Unknown Source) ~[xercesImpl-2.12.0.jar:na]
	at org.apache.xerces.impl.xs.XMLSchemaValidator.findSchemaGrammar(Unknown Source) ~[xercesImpl-2.12.0.jar:na]
	at org.apache.xerces.impl.xs.XMLSchemaValidator.getGlobalElementDecl(Unknown Source) ~[xercesImpl-2.12.0.jar:na]
	at org.apache.xerces.impl.xs.SubstitutionGroupHandler.getMatchingElemDecl(Unknown Source) ~[xercesImpl-2.12.0.jar:na]
	at org.apache.xerces.impl.xs.models.XSDFACM.oneTransition(Unknown Source) ~[xercesImpl-2.12.0.jar:na]
	at org.apache.xerces.impl.xs.XMLSchemaValidator.handleStartElement(Unknown Source) ~[xercesImpl-2.12.0.jar:na]
	at org.apache.xerces.impl.xs.XMLSchemaValidator.startElement(Unknown Source) ~[xercesImpl-2.12.0.jar:na]
	at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source) ~[xercesImpl-2.12.0.jar:2.12.0]
	at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source) ~[xercesImpl-2.12.0.jar:2.12.0]
	at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source) ~[xercesImpl-2.12.0.jar:2.12.0]
	at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source) ~[xercesImpl-2.12.0.jar:na]
	at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source) ~[xercesImpl-2.12.0.jar:na]
	at org.apache.xerces.parsers.XMLParser.parse(Unknown Source) ~[xercesImpl-2.12.0.jar:na]
	at org.apache.xerces.parsers.DOMParser.parse(Unknown Source) ~[xercesImpl-2.12.0.jar:na]
	at org.apache.xerces.jaxp.DocumentBuilderImpl.parse(Unknown Source) ~[xercesImpl-2.12.0.jar:na]
	at org.springframework.beans.factory.xml.DefaultDocumentLoader.loadDocument(DefaultDocumentLoader.java:77) ~[spring-beans-5.3.23.jar:5.3.23]
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadDocument(XmlBeanDefinitionReader.java:432) ~[spring-beans-5.3.23.jar:5.3.23]
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:390) ~[spring-beans-5.3.23.jar:5.3.23]
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:338) ~[spring-beans-5.3.23.jar:5.3.23]
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:310) ~[spring-beans-5.3.23.jar:5.3.23]
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:196) ~[spring-beans-5.3.23.jar:5.3.23]
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:232) ~[spring-beans-5.3.23.jar:5.3.23]
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:203) ~[spring-beans-5.3.23.jar:5.3.23]
	at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:125) ~[spring-web-5.3.23.jar:5.3.23]
	at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:94) ~[spring-web-5.3.23.jar:5.3.23]
	at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:130) ~[spring-context-5.3.23.jar:5.3.23]
	at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:671) ~[spring-context-5.3.23.jar:5.3.23]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:553) ~[spring-context-5.3.23.jar:5.3.23]
	at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:702) ~[spring-webmvc-5.3.23.jar:5.3.23]
	at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:668) ~[spring-webmvc-5.3.23.jar:5.3.23]
	at com.haulmont.addon.saml.servlet.SamlDispatcherServlet.initWebApplicationContext(SamlDispatcherServlet.java:80) ~[saml-addon-web-0.5.2.jar:na]
	at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:530) ~[spring-webmvc-5.3.23.jar:5.3.23]
	at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:170) ~[spring-webmvc-5.3.23.jar:5.3.23]
	at javax.servlet.GenericServlet.init(GenericServlet.java:158) ~[servlet-api.jar:4.0.FR]
	at com.haulmont.addon.saml.servlet.SamlDispatcherServlet.init(SamlDispatcherServlet.java:98) ~[saml-addon-web-0.5.2.jar:na]
	at com.haulmont.addon.saml.servlet.SamlServletInitializer.init(SamlServletInitializer.java:57) ~[saml-addon-web-0.5.2.jar:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
	at org.springframework.context.event.ApplicationListenerMethodAdapter.doInvoke(ApplicationListenerMethodAdapter.java:344) ~[spring-context-5.3.23.jar:5.3.23]
	at org.springframework.context.event.ApplicationListenerMethodAdapter.processEvent(ApplicationListenerMethodAdapter.java:229) ~[spring-context-5.3.23.jar:5.3.23]
	at org.springframework.context.event.ApplicationListenerMethodAdapter.onApplicationEvent(ApplicationListenerMethodAdapter.java:166) ~[spring-context-5.3.23.jar:5.3.23]
	at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176) ~[spring-context-5.3.23.jar:5.3.23]
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169) ~[spring-context-5.3.23.jar:5.3.23]
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143) ~[spring-context-5.3.23.jar:5.3.23]
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:421) ~[spring-context-5.3.23.jar:5.3.23]
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:378) ~[spring-context-5.3.23.jar:5.3.23]
	at com.haulmont.cuba.core.sys.EventsImpl.publish(EventsImpl.java:33) ~[cuba-global-7.2.20.jar:7.2.20]
	at com.haulmont.cuba.web.sys.WebEvents.publish(WebEvents.java:36) ~[cuba-web-7.2.20.jar:7.2.20]
	at com.haulmont.cuba.core.sys.AbstractWebAppContextLoader.contextInitialized(AbstractWebAppContextLoader.java:92) ~[cuba-global-7.2.20.jar:7.2.20]
	at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4678) ~[catalina.jar:9.0.38]
	at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5139) ~[catalina.jar:9.0.38]
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[catalina.jar:9.0.38]
	at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:717) ~[catalina.jar:9.0.38]
	at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:690) ~[catalina.jar:9.0.38]
	at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:706) ~[catalina.jar:9.0.38]
	at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1133) ~[catalina.jar:9.0.38]
	at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:1866) ~[catalina.jar:9.0.38]
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) ~[na:na]
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
	at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) ~[tomcat-util.jar:9.0.38]
	at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:118) ~[na:na]
	at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:1045) ~[catalina.jar:9.0.38]
	at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:429) ~[catalina.jar:9.0.38]
	at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1576) ~[catalina.jar:9.0.38]
	at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:309) ~[catalina.jar:9.0.38]
	at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:123) ~[catalina.jar:9.0.38]
	at org.apache.catalina.util.LifecycleBase.setStateInternal(LifecycleBase.java:423) ~[catalina.jar:9.0.38]
	at org.apache.catalina.util.LifecycleBase.setState(LifecycleBase.java:366) ~[catalina.jar:9.0.38]
	at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:936) ~[catalina.jar:9.0.38]
	at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:843) ~[catalina.jar:9.0.38]
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[catalina.jar:9.0.38]
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1384) ~[catalina.jar:9.0.38]
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1374) ~[catalina.jar:9.0.38]
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
	at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) ~[tomcat-util.jar:9.0.38]
	at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140) ~[na:na]
	at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909) ~[catalina.jar:9.0.38]
	at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:262) ~[catalina.jar:9.0.38]
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[catalina.jar:9.0.38]
	at org.apache.catalina.core.StandardService.startInternal(StandardService.java:421) ~[catalina.jar:9.0.38]
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[catalina.jar:9.0.38]
	at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:930) ~[catalina.jar:9.0.38]
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[catalina.jar:9.0.38]
	at org.apache.catalina.startup.Catalina.start(Catalina.java:772) ~[catalina.jar:9.0.38]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
	at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:342) ~[bootstrap.jar:9.0.38]
	at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:473) ~[bootstrap.jar:9.0.38]
Caused by: java.io.FileNotFoundException: http://www.springframework.org/schema/security/spring-security.xsd
	at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1920) ~[na:na]
	at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1520) ~[na:na]
	at org.apache.xerces.impl.XMLEntityManager.setupCurrentEntity(Unknown Source) ~[xercesImpl-2.12.0.jar:2.12.0]
	at org.apache.xerces.impl.XMLVersionDetector.determineDocVersion(Unknown Source) ~[xercesImpl-2.12.0.jar:2.12.0]
	at org.apache.xerces.impl.xs.opti.SchemaParsingConfig.parse(Unknown Source) ~[xercesImpl-2.12.0.jar:na]
	at org.apache.xerces.impl.xs.opti.SchemaParsingConfig.parse(Unknown Source) ~[xercesImpl-2.12.0.jar:na]
	at org.apache.xerces.impl.xs.opti.SchemaDOMParser.parse(Unknown Source) ~[xercesImpl-2.12.0.jar:na]
	... 94 common frames omitted

See forum topic

Exception when trying to save changes

Environment

  • Platform version: 7.2.0
  • Addon version: 0.4.0

Description of the bug or enhancement

  • Minimal reproducible example
  1. Administration โ†’ SAML
  2. Select a SAML connection
  3. Click Create
  4. Set Name, SSO Path, Default Access Group, Processing Service
  5. Select an incorrect key
  6. Set Service provider identity
  7. Click Refresh (for Service provider identity)
  8. Set Identity provider metadata = http://idp.ssocircle.com/idp-meta.xml
  9. Click Refresh (for Identity provider metadata)
  10. Click OK
  11. Click Edit
  12. Change Active
  13. Click OK

image
14. Click Close
15. Click OK

  • Expected behavior
    SAML connection editor is canceled
  • Actual behavior
    image

0.1 version uses wrong CUBA version

A topic on support forum: link

Environment

  • Platform version: 6.10
  • Addon version: 0.1

Description of the bug or enhancement

Addon version 0.1 is released with CUBA 7.0.4, but it should use 6.10 version

Upgrade add-on to CUBA 7.1 platform version.

Upgrade add-on to CUBA 7.1 platform version.
Snapshot add-on version should be updated to 0.2.
Current releases/cuba_7.0 branch should be merged from the master. Create this branch if it does not exist.

Occasional CredentialsExpiredException

Environment

  • Platform version: 7.2
  • Addon version: 0.5.0
  • GSuite as IDP

Description of the bug or enhancement

From time to time application fails to login user via SAML showing the following error:

2021-02-18 13:22:08.798 DEBUG [qtp2053591126-7905] org.opensaml.common.binding.decoding.BaseSAMLMessageDecoder - SAML message intended destination endpoint matched recipient endpoint
2021-02-18 13:22:08.802 ERROR [qtp2053591126-7905] com.haulmont.addon.saml.saml.authentication.SamlAuthenticationFailureHandler - Failed to login by saml
org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
	at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:101) ~[shared/:na]
	at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174) ~[shared/:na]
	at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:92) ~[shared/:na]
	at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212) ~[shared/:na]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[shared/:na]
	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214) ~[shared/:na]
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:185) ~[shared/:na]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[shared/:na]
	at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66) ~[shared/:na]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[shared/:na]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[shared/:na]
	at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) ~[shared/:na]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[shared/:na]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[shared/:na]
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) ~[shared/:na]
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[shared/:na]
	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214) ~[shared/:na]
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177) ~[shared/:na]
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358) ~[shared/:na]
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271) ~[shared/:na]
	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) ~[app.jar:na]
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1634) ~[app.jar:na]
	at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:108) ~[shared/:na]
	at com.haulmont.addon.saml.web.security.saml.SamlLoginHttpRequestFilter.doFilter(SamlLoginHttpRequestFilter.java:81) ~[classes/:na]
	at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113) ~[shared/:na]
	at org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:74) ~[shared/:na]
	at com.haulmont.cuba.web.sys.CubaHttpFilter.doFilter(CubaHttpFilter.java:93) ~[classes/:na]
	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) ~[app.jar:na]
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642) ~[app.jar:na]
	at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:228) ~[app.jar:na]
	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) ~[app.jar:na]
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642) ~[app.jar:na]
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:572) ~[app.jar:na]
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) ~[app.jar:na]
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:602) ~[app.jar:na]
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) ~[app.jar:na]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235) ~[app.jar:na]
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1612) ~[app.jar:na]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233) ~[app.jar:na]
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1434) ~[app.jar:na]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188) ~[app.jar:na]
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:512) ~[app.jar:na]
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1582) ~[app.jar:na]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186) ~[app.jar:na]
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1349) ~[app.jar:na]
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) ~[app.jar:na]
	at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:146) ~[app.jar:na]
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) ~[app.jar:na]
	at org.eclipse.jetty.server.Server.handle(Server.java:516) ~[app.jar:na]
	at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:383) ~[app.jar:na]
	at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:556) ~[app.jar:na]
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:375) ~[app.jar:na]
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:273) ~[app.jar:na]
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) ~[app.jar:na]
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105) ~[app.jar:na]
	at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.onFillable(SslConnection.java:540) ~[app.jar:na]
	at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:395) ~[app.jar:na]
	at org.eclipse.jetty.io.ssl.SslConnection$2.succeeded(SslConnection.java:161) ~[app.jar:na]
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105) ~[app.jar:na]
	at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104) ~[app.jar:na]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336) ~[app.jar:na]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313) ~[app.jar:na]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171) ~[app.jar:na]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129) ~[app.jar:na]
	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:375) ~[app.jar:na]
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:773) ~[app.jar:na]
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:905) ~[app.jar:na]
	at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]
Caused by: org.opensaml.common.SAMLException: Response doesn't have any valid assertion which would pass subject validation
	at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:265) ~[shared/:na]
	at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:88) ~[shared/:na]
	... 67 common frames omitted
Caused by: org.springframework.security.authentication.CredentialsExpiredException: Authentication statement is too old to be used with value 2021-02-17T13:21:10.000Z
	at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.verifyAuthenticationStatement(WebSSOProfileConsumerImpl.java:574) ~[shared/:na]
	at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.verifyAssertion(WebSSOProfileConsumerImpl.java:342) ~[shared/:na]
	at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:250) ~[shared/:na]
	... 68 common frames omitted
2021-02-18 13:22:08.810 DEBUG [qtp2053591126-7905] com.haulmont.addon.saml.saml.authentication.SamlAuthenticationFailureHandler - Using default Url: /
2021-02-18 13:22:09.019 DEBUG [qtp2053591126-7859] com.haulmont.cuba.web.App - Initializing application
2021-02-18 13:22:09.023 DEBUG [qtp2053591126-7859/app/anonymous] com.haulmont.cuba.web.DefaultApp - connectionStateChanged connected: true, authenticated: false
2021-02-18 13:22:09.023 DEBUG [qtp2053591126-7859/app/anonymous] com.haulmont.cuba.web.App - Closing all windows in all UIs
2021-02-18 13:22:09.033 DEBUG [qtp2053591126-7859/app-core/admin] com.haulmont.cuba.core.app.RdbmsStore - loadList: metaClass=samladdon$SamlConnection, view=com.haulmont.addon.saml.entity.SamlConnection/_minimal, query=Query{queryString='select e from samladdon$SamlConnection e where e.active = true order by e.ssoPath', condition=null, sort=null, firstResult=0, maxResults=0}
2021-02-18 13:24:23.449 DEBUG [cuba_core_scheduler-6] com.haulmont.cuba.core.app.queryresults.QueryResultsManager - Delete query results for inactive user sessions

Looks like this error usually appears after long time from last login via Google IDP.
Increasing the cuba.addon.saml.maxAuthenticationAgeSec doesn't seem to help.
Another thing is that logging out from Google before logging into SAML app helps to overcome the problem.

Error: User can't refresh Identity provider metadata

Environment

  • Addon version: 0.1.2

Description of the bug or enhancement

Run saml demo

  1. Administration โ†’ SAML
  2. Select a SAML connection
  3. Click Create
  4. Set Identity provider metadata = http://idp.ssocircle.com/idp-meta.xml
  5. Click Refresh (for Identity provider metadata)

Expected result: metadata were refreshed
Actual result: error message NoSuchMethodError: com.haulmont.cuba.gui.executors.BackgroundTask.(JLcom/haulmont/cuba/gui/components/Frame;)V

IDP initiated SSO doesn't work

Environment

  • Platform version: 7.2
  • Addon version: 0.4.1

Description of the bug or enhancement

The case when authentication is initiated by IDP currently doesn't work.
The problem is that in this case the tenant attribute is not set to the session (and cannot be set, because providing it as a URL parameter is not correct).
See the comment.

Possible solution: it is needed to either provide a way to put the tenant parameter with the first request to SP or determine the appropriate SAML connection based on the information provided by IDP.

Login stalls when webserver running on the root path

Environment

  • Platform version: 6.8.10
  • Addon version: 0.1-SNAPSHOT

Description of the bug or enhancement

When the application is deployed on the root of the webserver (e.g. https://app.compancy.com/) and SAML authentication is initiated (e.g. through https://app.compancy.com/sso?), the authentication succeeds but the client browser stalls on a blank screen (showing the url: https://app.compancy.com/sso). When removing the extension (/sso), the application is shown normally without further login/redirects.

If the webserver running on the default path (e.g. https://app.compancy.com/app) all works correctly.

Provide metadata from SP as url/file

Environment

  • Platform version: 6.8.10
  • Addon version: 0.1-SNAPSHOT

Description of the bug or enhancement

Currently, we provide the metadata from the Cuba app (as being the SP) through a file which we create by copying the XML into a file and sent it to the customer. This is inconvenient and it would be great if we would only need to communicate a url (e.g. https://app.compancy.com/saml/metadata/entity-id). Alternatively, it would be great to have a download option from the Cuba app for the XML file.

Failed to determinate SAML connection after redirecting back from IDP

Environment

  • Platform version: 7.2
  • Addon version: 0.4.1
  • HTTPs enabled
  • Browser: Chrome (in most cases)

Description of the bug or enhancement

  • Try login to CUBA app with HTTPs enabled via IDP
  • When redirecting back from IDP this error occurs:
java.lang.RuntimeException: Failed to determinate SAML connection
	com.haulmont.addon.saml.saml.internal.impl.SamlConnectionContextProviderImpl.populateConnection(SamlConnectionContextProviderImpl.java:157)
	com.haulmont.addon.saml.saml.internal.impl.SamlConnectionContextProviderImpl.getLocalEntity(SamlConnectionContextProviderImpl.java:109)
	org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:84)
	org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
	org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:185)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66)
	org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
	org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
	org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
	org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
	org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:108)
	com.haulmont.addon.saml.web.security.saml.SamlLoginHttpRequestFilter.doFilter(SamlLoginHttpRequestFilter.java:83)
	org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
	org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:74)
	com.haulmont.cuba.web.sys.CubaHttpFilter.doFilter(CubaHttpFilter.java:93)

The root cause of the error is that JSESSIONID cookie doesn't have attribute SameSite specified. Chrome defaults it to SameSite=Lax and then blocks it because the request was made from a different site (IDP). It leads to invalidating the current session and losing the tenant attribute which causes the error above.

Solution:

Setup SameSite=None cookie policy.

  1. Tomcat:
    In the webapps/app/META-INF/context.xml specify the CookieProcessor:
<Context>
   ...
   <CookieProcessor sameSiteCookies="none" />
   ...
</Context>
  1. Jetty (UberJAR):
    Open the web.xml in the web-module: web/WEB-INF/web.xml. Specify the following session-config:
</web-app>
   ...
    <session-config>
        <cookie-config>
            <comment>__SAME_SITE_NONE__</comment>
        </cookie-config>
    </session-config>
</web-app>

Re-build uberJar.

The above methods work for Tomcat (9.0.28 and later) and UberJAR versions that come with CUBA Plugin 7.2.9.

java.lang.NoClassDefFoundError: Could not initialize class org.apache.commons.ssl.TrustMaterial after redirecting back from IDP

In case of running an application on Java 9+, the error appears after redirecting back from IDP:

java.lang.NoClassDefFoundError: Could not initialize class org.apache.commons.ssl.TrustMaterial
	at org.opensaml.xml.security.x509.X509Util.decodeCertificate(X509Util.java:359)
	at org.opensaml.xml.security.keyinfo.KeyInfoHelper.getCertificate(KeyInfoHelper.java:201)
	at org.opensaml.xml.security.keyinfo.KeyInfoHelper.getCertificates(KeyInfoHelper.java:176)
	at org.opensaml.xml.security.keyinfo.provider.InlineX509DataProvider.extractCertificates(InlineX509DataProvider.java:192)
	at org.opensaml.xml.security.keyinfo.provider.InlineX509DataProvider.process(InlineX509DataProvider.java:126)
	at org.opensaml.xml.security.keyinfo.BasicProviderKeyInfoCredentialResolver.processKeyInfoChild(BasicProviderKeyInfoCredentialResolver.java:300)
	at org.opensaml.xml.security.keyinfo.BasicProviderKeyInfoCredentialResolver.processKeyInfoChildren(BasicProviderKeyInfoCredentialResolver.java:256)
	at org.opensaml.xml.security.keyinfo.BasicProviderKeyInfoCredentialResolver.processKeyInfo(BasicProviderKeyInfoCredentialResolver.java:190)
	at org.opensaml.xml.security.keyinfo.BasicProviderKeyInfoCredentialResolver.resolveFromSource(BasicProviderKeyInfoCredentialResolver.java:149)
	at org.opensaml.xml.security.credential.AbstractCriteriaFilteringCredentialResolver.resolve(AbstractCriteriaFilteringCredentialResolver.java:57)
	at org.opensaml.xml.security.credential.AbstractCriteriaFilteringCredentialResolver.resolve(AbstractCriteriaFilteringCredentialResolver.java:37)
	at org.opensaml.security.MetadataCredentialResolver.retrieveFromMetadata(MetadataCredentialResolver.java:275)
	at org.springframework.security.saml.trust.MetadataCredentialResolver.retrieveFromMetadata(MetadataCredentialResolver.java:123)
	at org.opensaml.security.MetadataCredentialResolver.resolveFromSource(MetadataCredentialResolver.java:178)
	at org.opensaml.xml.security.credential.AbstractCriteriaFilteringCredentialResolver.resolve(AbstractCriteriaFilteringCredentialResolver.java:57)
	at org.opensaml.xml.security.credential.AbstractCriteriaFilteringCredentialResolver.resolve(AbstractCriteriaFilteringCredentialResolver.java:37)
	at org.opensaml.xml.signature.impl.ExplicitKeySignatureTrustEngine.validate(ExplicitKeySignatureTrustEngine.java:98)
	at org.opensaml.xml.signature.impl.ExplicitKeySignatureTrustEngine.validate(ExplicitKeySignatureTrustEngine.java:49)
	at org.springframework.security.saml.websso.AbstractProfileBase.verifySignature(AbstractProfileBase.java:271)
	at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.verifyAssertionSignature(WebSSOProfileConsumerImpl.java:419)
	at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.verifyAssertion(WebSSOProfileConsumerImpl.java:292)
	at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:214)
	at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:88)
	at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174)
	at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:92)
	at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:185)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1602)
	at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:108)
	at com.haulmont.addon.saml.web.security.saml.SamlLoginHttpRequestFilter.doFilter(SamlLoginHttpRequestFilter.java:81)
	at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
	at org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:74)
	at com.haulmont.cuba.web.sys.CubaHttpFilter.doFilter(CubaHttpFilter.java:93)
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
	at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:214)
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1610)
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:540)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:146)
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:257)
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1711)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255)
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1347)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203)
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:480)
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1678)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201)
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1249)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144)
	at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:152)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
	at org.eclipse.jetty.server.Server.handle(Server.java:505)
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:370)
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:267)
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305)
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
	at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.onFillable(SslConnection.java:427)
	at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:321)
	at org.eclipse.jetty.io.ssl.SslConnection$2.succeeded(SslConnection.java:159)
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
	at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:333)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:310)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:168)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:126)
	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:366)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:781)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:917)
	at java.base/java.lang.Thread.run(Thread.java:834)

See related issue: spring-attic/spring-security-saml#263.
It's needed to update the Spring SAML version.

Environment

  • Platform version: 7.2.7
  • Addon version: 0.4.1
  • Java: 9+

Cannot generate metadata with PKCS12 keystore

In case of using a keystore of PKCS12 type, there is a problem when generating SP metadata:
Metadata view is not available. Error in SP metadata: invalid null input.

The cause of the error is that the application is not able to get the certificate chain for an alias entry, even if the keytool utility shows that the entry does have the corresponding certificate chain.

Environment

  • Platform version: 7.2.7
  • Addon version: 0.4.1
  • Java 11 (openjdk version "11.0.6")

User can't refresh Server Provider Identity (NoSuchMethodError)

Environment

  • Addon version: 0.1.1

Description of the bug or enhancement

  1. Click Administration -> SAML
  2. Click Create
  3. Set Server Provider Identity
  4. Click Refresh

Expected result: Server Provider Identity was set (Field below isn't empty)
Actual reuslt: NoSuchMethodError: com.haulmont.cuba.gui.executors.BackgroundTask.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.