package eu.dnetlib.organizations; import java.util.HashSet; import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest; import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService; import org.springframework.security.oauth2.client.oidc.web.logout.OidcClientInitiatedLogoutSuccessHandler; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.userinfo.OAuth2UserService; import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser; import org.springframework.security.oauth2.core.oidc.user.OidcUser; import org.springframework.security.web.access.AccessDeniedHandler; import eu.dnetlib.organizations.controller.UserInfo; import eu.dnetlib.organizations.controller.UserRole; import eu.dnetlib.organizations.model.User; import eu.dnetlib.organizations.utils.DatabaseUtils; import eu.dnetlib.organizations.utils.OpenOrgsConstants; @Profile("!dev") @Configuration @EnableWebSecurity public class OAuth2WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private DatabaseUtils databaseUtils; @Autowired private ClientRegistrationRepository clientRegistrationRepository; @Value("${openaire.api.valid.subnet}") private String openaireApiValidSubnet; @Value("${openaire.override.logout.url}") private String openaireLogoutUrl; private static Logger logger = LoggerFactory.getLogger(OAuth2WebSecurityConfig.class); @Override protected void configure(final HttpSecurity http) throws Exception { http.csrf() .disable() .authorizeRequests() .antMatchers("/main", "/api/**") .hasAnyRole(OpenOrgsConstants.VALID_ROLES) .antMatchers("/registration_api/**") .hasRole(OpenOrgsConstants.NOT_AUTORIZED_ROLE) .antMatchers("/", "/resources/**", "/webjars/**") .permitAll() .antMatchers("/oa_api/**") .hasIpAddress(openaireApiValidSubnet) .anyRequest() .authenticated() .and() .exceptionHandling() .accessDeniedHandler(accessDeniedHandler()) .and() .logout() .logoutSuccessHandler(oidcLogoutSuccessHandler()) .invalidateHttpSession(true) .clearAuthentication(true) .deleteCookies("JSESSIONID") .and() .oauth2Login(oauth2 -> oauth2.userInfoEndpoint(userInfo -> userInfo.oidcUserService(this.oidcUserService()))); } private AccessDeniedHandler accessDeniedHandler() { return (req, res, e) -> { final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication != null) { logger.warn(String .format("User '%s' (%s) attempted to access the protected URL: %s", UserInfo.getEmail(authentication), req .getRemoteAddr(), req.getRequestURI())); } if (UserInfo.isNotAuthorized(authentication)) { res.sendRedirect(req.getContextPath() + "/authorizationRequest"); } else { res.sendRedirect(req.getContextPath() + "/alreadyRegistered"); } }; } private OidcClientInitiatedLogoutSuccessHandler oidcLogoutSuccessHandler() { final OidcClientInitiatedLogoutSuccessHandler handler = new OidcClientInitiatedLogoutSuccessHandler(clientRegistrationRepository); // NB: // The same URL must be configured server side: // Manage Clients > Edit Client > Other > Post-Logout Redirect handler.setPostLogoutRedirectUri("{baseUrl}"); handler.setRedirectStrategy((req, res, url) -> { if (StringUtils.isNotBlank(openaireLogoutUrl)) { logger.info("Performing remote logout: " + openaireLogoutUrl); res.sendRedirect(openaireLogoutUrl); } else { logger.info("Performing remote logout: " + url); res.sendRedirect(url); } }); return handler; } private OAuth2UserService oidcUserService() { final OidcUserService delegate = new OidcUserService(); return (userRequest) -> { final OidcUser oidcUser = delegate.loadUser(userRequest); final String role = "ROLE_" + OpenOrgsConstants.OPENORGS_ROLE_PREFIX + databaseUtils.findUser(oidcUser.getEmail()) .map(User::getRole) .filter(StringUtils::isNotBlank) .orElse(UserRole.NOT_AUTHORIZED.toString()); final Set mappedAuthorities = new HashSet<>(); mappedAuthorities.add(new SimpleGrantedAuthority(role)); return new DefaultOidcUser(mappedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo()); }; } // https://www.baeldung.com/spring-security-openid-connect // https://github.com/mitreid-connect/ // https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/tree/master/openid-connect-client // https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/wiki/Client-configuration // https://svn.driver.research-infrastructures.eu/driver/dnet45/modules/uoa-login-core/trunk/ // https://svn.driver.research-infrastructures.eu/driver/dnet45/modules/uoa-user-management/trunk/ // https://svn.driver.research-infrastructures.eu/driver/dnet45/modules/dnet-openaire-users/trunk/ // https://svn.driver.research-infrastructures.eu/driver/dnet45/modules/dnet-login/trunk/ // Aprire Ticket a GRNET con Argiro e Katerina come watchers }