Skip to content

Commit

Permalink
Add saml configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
APiankouski committed Oct 23, 2024
1 parent b5eb859 commit 5aea35e
Show file tree
Hide file tree
Showing 3 changed files with 235 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright 2024 EPAM Systems
*
* 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.epam.reportportal.auth.config.saml;


import com.epam.reportportal.auth.AuthFailureHandler;
import com.epam.reportportal.auth.integration.saml.ReportPortalSamlAuthenticationManager;
import com.epam.reportportal.auth.integration.saml.SamlAuthSuccessHandler;
import com.epam.reportportal.auth.integration.saml.SamlUserReplicator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.web.authentication.Saml2WebSsoAuthenticationFilter;
import org.springframework.security.web.DefaultSecurityFilterChain;

/**
* @author <a href="mailto:andrei_piankouski@epam.com">Andrei Piankouski</a>
*/
public class Saml2AuthenticationConfigurer extends
SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {

private static final Logger LOGGER = LoggerFactory.getLogger(Saml2AuthenticationConfigurer.class);

private SamlAuthSuccessHandler successHandler;

private AuthFailureHandler failureHandler;

private SamlUserReplicator samlUserReplicator;

private RelyingPartyRegistrationRepository relyingPartyRegistrationRepository;

public Saml2AuthenticationConfigurer(SamlAuthSuccessHandler successHandler,
AuthFailureHandler failureHandler, SamlUserReplicator samlUserReplicator,
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) {
this.successHandler = successHandler;
this.failureHandler = failureHandler;
this.samlUserReplicator = samlUserReplicator;
this.relyingPartyRegistrationRepository = relyingPartyRegistrationRepository;
}

@Override
public void configure(HttpSecurity http) {
LOGGER.error("Saml2AuthenticationConfigurer: " + http);
Saml2WebSsoAuthenticationFilter saml2Filter = new Saml2WebSsoAuthenticationFilter(relyingPartyRegistrationRepository);
saml2Filter.setAuthenticationManager(new ReportPortalSamlAuthenticationManager(samlUserReplicator));
saml2Filter.setAuthenticationSuccessHandler(successHandler);
saml2Filter.setAuthenticationFailureHandler(failureHandler);

http.addFilterAfter(saml2Filter, Saml2WebSsoAuthenticationFilter.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/*
* Copyright 2024 EPAM Systems
*
* 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.epam.reportportal.auth.config.saml;

import static org.springframework.security.config.Customizer.withDefaults;

import com.epam.reportportal.auth.AuthFailureHandler;
import com.epam.reportportal.auth.integration.parameter.SamlParameter;
import com.epam.reportportal.auth.integration.saml.ReportPortalSamlAuthenticationManager;
import com.epam.reportportal.auth.integration.saml.SamlAuthSuccessHandler;
import com.epam.reportportal.auth.integration.saml.SamlUserReplicator;
import com.epam.reportportal.auth.util.CertificationUtil;
import com.epam.ta.reportportal.dao.IntegrationRepository;
import com.epam.ta.reportportal.dao.IntegrationTypeRepository;
import com.epam.ta.reportportal.entity.integration.Integration;
import com.epam.ta.reportportal.entity.integration.IntegrationType;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.saml2.core.Saml2X509Credential;
import org.springframework.security.saml2.provider.service.metadata.OpenSamlMetadataResolver;
import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrations;
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter;
import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
import org.springframework.security.saml2.provider.service.web.Saml2MetadataFilter;
import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver;

/**
* @author <a href="mailto:andrei_piankouski@epam.com">Andrei Piankouski</a>
*/
@Configuration
@Order(4)
public class SamlSecurityConfiguration extends WebSecurityConfigurerAdapter {

@Value("${rp.auth.saml.base-path}")
private String basePath;

@Value("${rp.auth.saml.entity-id}")
private String entityId;

@Value("${rp.auth.saml.key-alias}")
private String keyAlias;

@Value("${rp.auth.saml.key-password}")
private String keyPassword;

@Value("${rp.auth.saml.key-store}")
private String keyStore;

@Value("${rp.auth.saml.key-store-password}")
private String keyStorePassword;

@Value("${rp.auth.saml.active-key-name}")
private String activeKeyName;

@Value("${rp.auth.saml.network-connection-timeout}")
private Integer networkConnectTimeout;

@Value("${rp.auth.saml.network-read-timeout}")
private Integer networkReadTimeout;

@Value("${rp.auth.saml.signed-requests}")
private Boolean signedRequests;

@Value("${rp.auth.saml.prefix}")
private String prefix;

@Autowired
private IntegrationTypeRepository integrationTypeRepository;

@Autowired
private IntegrationRepository integrationRepository;

@Autowired
private SamlAuthSuccessHandler successHandler;

@Autowired
private AuthFailureHandler failureHandler;

@Autowired
private SamlUserReplicator samlUserReplicator;


@Override
protected void configure(HttpSecurity http) throws Exception {

// add auto-generation of ServiceProvider Metadata
Converter<HttpServletRequest, RelyingPartyRegistration> relyingPartyRegistrationResolver = new DefaultRelyingPartyRegistrationResolver(relyingParty());
Saml2MetadataFilter filter = new Saml2MetadataFilter(relyingPartyRegistrationResolver, new OpenSamlMetadataResolver());

http
// Configure SAML 2.0 Login
.saml2Login(
samlLogin ->
samlLogin.loginPage("/saml/sp/discovery")
.successHandler(successHandler)
.failureHandler(failureHandler)
.authenticationManager(new ReportPortalSamlAuthenticationManager(samlUserReplicator))

)
.addFilterBefore(filter, Saml2WebSsoAuthenticationFilter.class)
.build();

}

@Bean
public RelyingPartyRegistrationRepository relyingParty() throws Exception {
IntegrationType samlIntegrationType = integrationTypeRepository.findByName("SAML")
.orElseThrow(() -> new RuntimeException("SAML Integration Type not found"));

List<Integration> providers = integrationRepository.findAllGlobalByType(samlIntegrationType);

X509Certificate certificate = CertificationUtil.getCertificateByName(keyAlias, keyStore,
keyStorePassword);
Saml2X509Credential credential = Saml2X509Credential.verification(certificate);

List<RelyingPartyRegistration> registrations = providers.stream().map(provider -> {
RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations
.fromMetadataLocation(SamlParameter.IDP_METADATA_URL.getParameter(provider).get())
.registrationId("report.portal.sp.id")
.entityId(entityId)
.assertionConsumerServiceLocation(SamlParameter.BASE_PATH.getParameter(provider).get())
.assertingPartyDetails(party -> party.entityId(SamlParameter.IDP_NAME.getParameter(provider).get())
.wantAuthnRequestsSigned(false)
// .singleSignOnServiceLocation(samlProperties.getAssertingpParty().getServiceLocation())
.singleSignOnServiceBinding(Saml2MessageBinding.POST))
.signingX509Credentials(c -> c.add(credential))
.build();
return relyingPartyRegistration;

}).collect(Collectors.toList());
return new InMemoryRelyingPartyRegistrationRepository(registrations);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import static com.epam.reportportal.auth.util.AuthUtils.CROP_DOMAIN;
import static com.epam.reportportal.auth.util.AuthUtils.NORMALIZE_STRING;

import com.epam.reportportal.auth.AdminPasswordInitializer;
import com.epam.reportportal.auth.event.activity.AssignUserEvent;
import com.epam.reportportal.auth.event.activity.ProjectCreatedEvent;
import com.epam.reportportal.auth.event.activity.UserCreatedEvent;
Expand All @@ -45,6 +46,10 @@
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
Expand All @@ -59,6 +64,8 @@
@Component
public class SamlUserReplicator extends AbstractUserReplicator {

private static final Logger LOGGER = LoggerFactory.getLogger(SamlUserReplicator.class);

private final IntegrationTypeRepository integrationTypeRepository;
private final IntegrationRepository integrationRepository;

Expand All @@ -80,6 +87,7 @@ public SamlUserReplicator(UserRepository userRepository, ProjectRepository proje

@Transactional
public User replicateUser(ReportPortalSamlAuthentication samlAuthentication) {
LOGGER.error("Start replication: " + samlAuthentication);
String userName = CROP_DOMAIN.apply(samlAuthentication.getPrincipalName());
Optional<User> userOptional = userRepository.findByLogin(userName);

Expand Down

0 comments on commit 5aea35e

Please sign in to comment.