Move all components from login-service to login-core

This commit is contained in:
Konstantinos Triantafyllou 2023-05-18 11:44:50 +03:00
commit 63d9be79c9
28 changed files with 1207 additions and 0 deletions

54
pom.xml Normal file
View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>eu.dnetlib</groupId>
<artifactId>uoa-spring-boot-parent</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>uoa-login-core</artifactId>
<version>2.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>uoa-login-core</name>
<scm>
<developerConnection>scm:git:gitea@code-repo.d4science.org:MaDgIK/uoa-login-core.git</developerConnection>
<tag>HEAD</tag>
</scm>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<timestampLogincORE>${maven.build.timestamp}</timestampLogincORE>
<maven.build.timestamp.format>E MMM dd HH:mm:ss z yyyy</maven.build.timestamp.format>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- Redis -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
<groupId>biz.paluch.redis</groupId>
<artifactId>lettuce</artifactId>
<version>4.3.3.Final</version>
</dependency>
<!-- Mitre -->
<dependency>
<groupId>org.mitre</groupId>
<artifactId>openid-connect-client</artifactId>
<version>1.3.0</version>
<exclusions>
<exclusion>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<finalName>uoa-login-core</finalName>
</build>
</project>

View File

@ -0,0 +1,38 @@
package eu.dnetlib.authentication.configuration;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("api")
public class APIProperties {
private String title;
private String description;
private String version;
public APIProperties() {
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
}

View File

@ -0,0 +1,14 @@
package eu.dnetlib.authentication.configuration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties({Properties.class, APIProperties.class})
@ComponentScan(basePackages = {"eu.dnetlib.authentication"})
public class AuthenticationConfiguration {
public AuthenticationConfiguration() {
}
}

View File

@ -0,0 +1,68 @@
package eu.dnetlib.authentication.configuration;
public class OIDC {
private String issuer;
private String home;
private String redirect;
private String id;
private String secret;
private String scope = "";
private String logout;
public String getIssuer() {
return issuer;
}
public void setIssuer(String issuer) {
this.issuer = issuer;
}
public String getHome() {
return home;
}
public void setHome(String home) {
this.home = home;
}
public String getRedirect() {
return redirect;
}
public void setRedirect(String redirect) {
this.redirect = redirect;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
public String getLogout() {
return logout;
}
public void setLogout(String logout) {
this.logout = logout;
}
}

View File

@ -0,0 +1,83 @@
package eu.dnetlib.authentication.configuration;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("authentication")
public class Properties {
private Redis redis = new Redis();
private OIDC oidc = new OIDC();
private String domain;
private String session;
private String accessToken;
private String redirect;
private String authoritiesMapper;
private Boolean keycloak;
public Properties() {
}
public Redis getRedis() {
return redis;
}
public void setRedis(Redis redis) {
this.redis = redis;
}
public OIDC getOidc() {
return oidc;
}
public void setOidc(OIDC oidc) {
this.oidc = oidc;
}
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
public String getSession() {
return session;
}
public void setSession(String session) {
this.session = session;
}
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public String getRedirect() {
return redirect;
}
public void setRedirect(String redirect) {
this.redirect = redirect;
}
public String getAuthoritiesMapper() {
return authoritiesMapper;
}
public void setAuthoritiesMapper(String authoritiesMapper) {
this.authoritiesMapper = authoritiesMapper;
}
public Boolean getKeycloak() {
return keycloak;
}
public void setKeycloak(Boolean keycloak) {
this.keycloak = keycloak;
}
}

View File

@ -0,0 +1,44 @@
package eu.dnetlib.authentication.configuration;
public class Redis {
private String host = "localhost";
private String port = "6379";
private String password;
public Redis() {
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public String getPort() {
return port;
}
public void setPort(String port) {
this.port = port;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "Redis{" +
"host='" + host + '\'' +
", port='" + port + '\'' +
", password='" + password + '\'' +
'}';
}
}

View File

@ -0,0 +1,51 @@
package eu.dnetlib.authentication.controllers;
import eu.dnetlib.authentication.configuration.Properties;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class HealthController {
private final Logger log = LogManager.getLogger(this.getClass());
private final Properties properties;
@Autowired
public HealthController(Properties properties) {
this.properties = properties;
}
@RequestMapping(value = {"", "/health_check"}, method = RequestMethod.GET)
public String hello() {
log.debug("Hello from Login service!");
return "Hello from Login service!";
}
@PreAuthorize("hasAnyAuthority('PORTAL_ADMINISTRATOR')")
@RequestMapping(value = "/health_check/advanced", method = RequestMethod.GET)
public Map<String, String> checkEverything() {
Map<String, String> response = new HashMap<>();
response.put("authentication.domain", properties.getDomain());
response.put("authentication.keycloak", properties.getKeycloak().toString());
response.put("authentication.redis.host", properties.getRedis().getHost());
response.put("authentication.oidc.issuer", properties.getOidc().getIssuer());
response.put("authentication.oidc.logout", properties.getOidc().getLogout());
response.put("authentication.oidc.home", properties.getOidc().getHome());
response.put("authentication.oidc.redirect", properties.getOidc().getRedirect());
response.put("authentication.oidc.scope", properties.getOidc().getScope());
response.put("authentication.oidc.id", properties.getOidc().getId());
response.put("authentication.oidc.secret", properties.getOidc().getSecret());
response.put("authentication.session", properties.getSession());
response.put("authentication.accessToken", properties.getAccessToken());
response.put("authentication.redirect", properties.getRedirect());
response.put("authentication.authorities-mapper", properties.getAuthoritiesMapper());
return response;
}
}

View File

@ -0,0 +1,45 @@
package eu.dnetlib.authentication.controllers;
import eu.dnetlib.authentication.entities.User;
import eu.dnetlib.authentication.configuration.Properties;
import eu.dnetlib.authentication.services.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@RestController
public class UserController {
private final UserInfoService userInfoService;
private final Properties properties;
@Autowired
public UserController(UserInfoService userInfoService, Properties properties) {
this.userInfoService = userInfoService;
this.properties = properties;
}
@RequestMapping(value = "/userInfo", method = RequestMethod.GET)
public ResponseEntity<User> getUserInfo() {
return ResponseEntity.ok(userInfoService.getUserInfo());
}
@RequestMapping(value = "/redirect",method = RequestMethod.GET)
public void redirect(HttpServletRequest request, HttpServletResponse response) throws IOException {
HttpSession session = request.getSession();
String redirect = (String) session.getAttribute("redirect");
session.removeAttribute("redirect");
if(redirect == null) {
redirect = properties.getRedirect();
}
session.invalidate();
response.sendRedirect(redirect);
}
}

View File

@ -0,0 +1,74 @@
package eu.dnetlib.authentication.entities;
import org.mitre.openid.connect.model.OIDCAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import java.util.Set;
import java.util.stream.Collectors;
public class User {
private String sub;
private String name;
private String given_name;
private String family_name;
private String email;
private Set<String> roles;
public User(OIDCAuthenticationToken token) {
this.sub = token.getUserInfo().getSub();
this.name = token.getUserInfo().getName();
this.given_name = token.getUserInfo().getGivenName();
this.family_name = token.getUserInfo().getFamilyName();
this.email = token.getUserInfo().getEmail();
this.roles = token.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet());
}
public String getSub() {
return sub;
}
public void setSub(String sub) {
this.sub = sub;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGiven_name() {
return given_name;
}
public void setGiven_name(String given_name) {
this.given_name = given_name;
}
public String getFamily_name() {
return family_name;
}
public void setFamily_name(String family_name) {
this.family_name = family_name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Set<String> getRoles() {
return roles;
}
public void setRoles(Set<String> roles) {
this.roles = roles;
}
}

View File

@ -0,0 +1,20 @@
package eu.dnetlib.authentication.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(value = HttpStatus.NOT_FOUND) // 404
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
public ResourceNotFoundException(String message, Throwable err) {
super(message, err);
}
public HttpStatus getStatus() {
return HttpStatus.NOT_FOUND;
}
}

View File

@ -0,0 +1,16 @@
package eu.dnetlib.authentication.security;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
public class CorsConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS")
.allowCredentials(true);
}
}

View File

@ -0,0 +1,43 @@
package eu.dnetlib.authentication.security;
import eu.dnetlib.authentication.configuration.Properties;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;
@EnableRedisHttpSession
@Configuration
public class RedisConfig {
private final Properties properties;
private static final Logger logger = LogManager.getLogger(RedisConfig.class);
@Autowired
public RedisConfig(Properties properties) {
this.properties = properties;
}
@Bean
public LettuceConnectionFactory connectionFactory() {
logger.info(String.format("Redis connection listens to %s:%s ", properties.getRedis().getHost(), properties.getRedis().getPort()));
LettuceConnectionFactory factory = new LettuceConnectionFactory(properties.getRedis().getHost(), Integer.parseInt(properties.getRedis().getPort()));
if (properties.getRedis().getPassword() != null) factory.setPassword(properties.getRedis().getPassword());
return factory;
}
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName(properties.getSession());
serializer.setCookiePath("/");
serializer.setDomainName(properties.getDomain());
return serializer;
}
}

View File

@ -0,0 +1,82 @@
package eu.dnetlib.authentication.security;
import eu.dnetlib.authentication.configuration.Properties;
import eu.dnetlib.authentication.security.oidc.OpenAIREAuthenticationFilter;
import eu.dnetlib.authentication.security.oidc.OpenAIREAuthenticationSuccessHandler;
import eu.dnetlib.authentication.security.oidc.OpenAIRELogoutHandler;
import eu.dnetlib.authentication.security.oidc.OpenAIRELogoutSuccessHandler;
import eu.dnetlib.authentication.utils.EntryPoint;
import org.mitre.openid.connect.client.OIDCAuthenticationProvider;
import org.mitre.openid.connect.client.service.ClientConfigurationService;
import org.mitre.openid.connect.client.service.IssuerService;
import org.mitre.openid.connect.client.service.ServerConfigurationService;
import org.mitre.openid.connect.client.service.impl.PlainAuthRequestUrlBuilder;
import org.mitre.openid.connect.client.service.impl.StaticAuthRequestOptionsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.web.authentication.www.BasicAuthenticationFilter;
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = true)
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final Properties properties;
private final EntryPoint entryPoint;
private final OIDCAuthenticationProvider provider;
private final IssuerService issuerService;
private final ServerConfigurationService serverConfigurationService;
private final ClientConfigurationService clientConfigurationService;
private final StaticAuthRequestOptionsService optionsService;
private final PlainAuthRequestUrlBuilder builder;
private final OpenAIREAuthenticationSuccessHandler authenticationSuccessHandler;
private final OpenAIRELogoutHandler logoutHandler;
private final OpenAIRELogoutSuccessHandler logoutSuccessHandler;
@Autowired
public WebSecurityConfig(Properties properties, EntryPoint entryPoint, OIDCAuthenticationProvider provider,
IssuerService issuerService, ServerConfigurationService serverConfigurationService,
ClientConfigurationService clientConfigurationService, StaticAuthRequestOptionsService optionsService,
PlainAuthRequestUrlBuilder builder, OpenAIREAuthenticationSuccessHandler authenticationSuccessHandler,
OpenAIRELogoutHandler logoutHandler, OpenAIRELogoutSuccessHandler logoutSuccessHandler) {
super();
this.properties = properties;
this.entryPoint = entryPoint;
this.provider = provider;
this.issuerService = issuerService;
this.serverConfigurationService = serverConfigurationService;
this.clientConfigurationService = clientConfigurationService;
this.optionsService = optionsService;
this.builder = builder;
this.authenticationSuccessHandler = authenticationSuccessHandler;
this.logoutHandler = logoutHandler;
this.logoutSuccessHandler = logoutSuccessHandler;
}
public OpenAIREAuthenticationFilter initFilter() throws Exception {
OpenAIREAuthenticationFilter filter = new OpenAIREAuthenticationFilter(properties);
filter.setAuthenticationManager(authenticationManagerBean());
filter.afterPropertiesSet();
filter.setIssuerService(issuerService);
filter.setServerConfigurationService(serverConfigurationService);
filter.setClientConfigurationService(clientConfigurationService);
filter.setAuthRequestOptionsService(optionsService);
filter.setAuthRequestUrlBuilder(builder);
filter.setAuthenticationSuccessHandler(authenticationSuccessHandler);
return filter;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authenticationProvider(provider);
http.addFilterBefore(initFilter(), BasicAuthenticationFilter.class);
http.httpBasic().authenticationEntryPoint(entryPoint);
http.logout().logoutUrl("/openid_logout").addLogoutHandler(logoutHandler)
.logoutSuccessHandler(logoutSuccessHandler).invalidateHttpSession(false);
http.authorizeRequests().anyRequest().permitAll();
}
}

View File

@ -0,0 +1,77 @@
package eu.dnetlib.authentication.security.initiliazers;
import eu.dnetlib.authentication.configuration.Properties;
import eu.dnetlib.authentication.security.oidc.OpenAIREAuthoritiesMapper;
import eu.dnetlib.authentication.security.oidc.OpenAIREUserInfoFetcher;
import eu.dnetlib.authentication.utils.PropertyReader;
import org.mitre.oauth2.model.ClientDetailsEntity;
import org.mitre.oauth2.model.RegisteredClient;
import org.mitre.openid.connect.client.OIDCAuthenticationProvider;
import org.mitre.openid.connect.config.ServerConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;
import java.util.HashSet;
@Configuration
public class Configurations {
private final Properties properties;
private final PropertyReader scopeReader;
private final OpenAIREAuthoritiesMapper authoritiesMapper;
private final OpenAIREUserInfoFetcher userInfoFetcher;
@Autowired
public Configurations(Properties properties, OpenAIREAuthoritiesMapper authoritiesMapper, OpenAIREUserInfoFetcher userInfoFetcher, PropertyReader scopeReader) {
this.properties = properties;
this.authoritiesMapper = authoritiesMapper;
this.userInfoFetcher = userInfoFetcher;
this.scopeReader = scopeReader;
}
@Bean
public OIDCAuthenticationProvider provider() {
OIDCAuthenticationProvider provider = new OIDCAuthenticationProvider();
if(properties.getKeycloak()) {
provider.setUserInfoFetcher(this.userInfoFetcher);
}
if(this.properties.getAuthoritiesMapper() != null && this.scopeReader.getScopes().contains(this.properties.getAuthoritiesMapper())) {
provider.setAuthoritiesMapper(this.authoritiesMapper);
}
return provider;
}
@Bean
public ServerConfiguration serverConfiguration() {
String issuer = properties.getOidc().getIssuer();
ServerConfiguration serverConfiguration = new ServerConfiguration();
serverConfiguration.setIssuer(issuer);
Boolean keycloak = properties.getKeycloak();
if(keycloak) {
serverConfiguration.setAuthorizationEndpointUri(issuer + "/protocol/openid-connect/auth");
serverConfiguration.setTokenEndpointUri(issuer + "/protocol/openid-connect/token");
serverConfiguration.setUserInfoUri(issuer + "/protocol/openid-connect/userinfo");
serverConfiguration.setJwksUri(issuer + "/protocol/openid-connect/certs");
} else {
serverConfiguration.setAuthorizationEndpointUri(issuer + "/authorize");
serverConfiguration.setTokenEndpointUri(issuer + "/token");
serverConfiguration.setUserInfoUri(issuer + "/userinfo");
serverConfiguration.setJwksUri(issuer + "/jwk");
}
serverConfiguration.setRevocationEndpointUri(issuer + "/revoke");
return serverConfiguration;
}
@Bean
public RegisteredClient registeredClient() {
RegisteredClient client = new RegisteredClient();
client.setClientId(properties.getOidc().getId());
client.setClientSecret(properties.getOidc().getSecret());
client.setScope(scopeReader.getScopes());
client.setTokenEndpointAuthMethod(ClientDetailsEntity.AuthMethod.SECRET_BASIC);
client.setRedirectUris(new HashSet<>(Arrays.asList(properties.getOidc().getHome(), properties.getOidc().getRedirect())));
return client;
}
}

View File

@ -0,0 +1,56 @@
package eu.dnetlib.authentication.security.initiliazers;
import eu.dnetlib.authentication.configuration.Properties;
import eu.dnetlib.authentication.utils.EntryPoint;
import eu.dnetlib.authentication.utils.PropertyReader;
import org.mitre.openid.connect.client.service.impl.PlainAuthRequestUrlBuilder;
import org.mitre.openid.connect.client.service.impl.StaticAuthRequestOptionsService;
import org.mitre.openid.connect.client.service.impl.StaticSingleIssuerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
@Configuration
public class Primitives {
private final Properties properties;
@Autowired
public Primitives(Properties properties) {
this.properties = properties;
}
@Bean
public PropertyReader scopeReader() {
return new PropertyReader(this.properties.getOidc().getScope());
}
@Bean
public DefaultWebSecurityExpressionHandler handler() {
return new DefaultWebSecurityExpressionHandler();
}
@Bean
public PlainAuthRequestUrlBuilder builder() {
return new PlainAuthRequestUrlBuilder();
}
@Bean
public StaticSingleIssuerService issuerService() {
StaticSingleIssuerService issuerService = new StaticSingleIssuerService();
issuerService.setIssuer(properties.getOidc().getIssuer());
return issuerService;
}
@Bean
public EntryPoint entryPoint() {
return new EntryPoint();
}
@Bean
public StaticAuthRequestOptionsService optionsService() {
return new StaticAuthRequestOptionsService();
}
}

View File

@ -0,0 +1,47 @@
package eu.dnetlib.authentication.security.initiliazers;
import eu.dnetlib.authentication.configuration.Properties;
import org.mitre.oauth2.model.RegisteredClient;
import org.mitre.openid.connect.client.service.impl.StaticClientConfigurationService;
import org.mitre.openid.connect.client.service.impl.StaticServerConfigurationService;
import org.mitre.openid.connect.config.ServerConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class Services {
private final Properties properties;
private final ServerConfiguration serverConfiguration;
private final RegisteredClient clientConfiguration;
@Autowired
public Services(Properties properties, ServerConfiguration serverConfiguration, RegisteredClient clientConfiguration) {
this.properties = properties;
this.serverConfiguration = serverConfiguration;
this.clientConfiguration = clientConfiguration;
}
@Bean
public StaticServerConfigurationService serverConfigurationService() {
StaticServerConfigurationService configurationService = new StaticServerConfigurationService();
Map<String, ServerConfiguration> servers = new HashMap<>();
servers.put(properties.getOidc().getIssuer(), serverConfiguration);
configurationService.setServers(servers);
return configurationService;
}
@Bean
public StaticClientConfigurationService clientConfigurationService() {
StaticClientConfigurationService configurationService = new StaticClientConfigurationService();
Map<String, RegisteredClient> clients = new HashMap<>();
clients.put(properties.getOidc().getIssuer(), clientConfiguration);
configurationService.setClients(clients);
return configurationService;
}
}

View File

@ -0,0 +1,28 @@
package eu.dnetlib.authentication.security.oidc;
import eu.dnetlib.authentication.configuration.Properties;
import eu.dnetlib.authentication.utils.Redirect;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.mitre.openid.connect.client.OIDCAuthenticationFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class OpenAIREAuthenticationFilter extends OIDCAuthenticationFilter {
private final static Logger logger = LogManager.getLogger(OpenAIREAuthenticationSuccessHandler.class);
private final Properties properties;
public OpenAIREAuthenticationFilter(Properties properties) {
super();
this.properties = properties;
}
@Override
protected void handleAuthorizationRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
Redirect.setRedirect(request, properties);
super.handleAuthorizationRequest(request, response);
}
}

View File

@ -0,0 +1,66 @@
package eu.dnetlib.authentication.security.oidc;
import com.google.gson.JsonParser;
import eu.dnetlib.authentication.configuration.Properties;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.mitre.openid.connect.model.OIDCAuthenticationToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.session.FindByIndexNameSessionRepository;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Base64;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Configuration
public class OpenAIREAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private static final Logger logger = LogManager.getLogger(OpenAIREAuthenticationSuccessHandler.class);
private final Properties properties;
@Autowired
public OpenAIREAuthenticationSuccessHandler(Properties properties) {
this.properties = properties;
}
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException {
OIDCAuthenticationToken token = (OIDCAuthenticationToken) authentication;
HttpSession session = request.getSession();
String redirect = (String) session.getAttribute("redirect");
session.setAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, token.getUserInfo().getSub());
try {
Cookie accessToken = new Cookie(properties.getAccessToken(), token.getAccessTokenValue());
String regex = "^([A-Za-z0-9-_=]+)\\.([A-Za-z0-9-_=]+)\\.?([A-Za-z0-9-_.+=]*)$";
Matcher matcher = Pattern.compile(regex).matcher(token.getAccessTokenValue());
if (matcher.find()) {
long exp = new JsonParser().parse(new String(Base64.getDecoder().decode(matcher.group(2)))).getAsJsonObject().get("exp").getAsLong();
accessToken.setMaxAge((int) (exp - (new Date().getTime() / 1000)));
} else {
accessToken.setMaxAge(3600);
}
accessToken.setPath("/");
accessToken.setDomain(properties.getDomain());
response.addCookie(accessToken);
if(redirect != null) {
response.sendRedirect(redirect);
session.removeAttribute("redirect");
} else {
response.sendRedirect(properties.getRedirect());
}
} catch (IOException e) {
logger.error("IOException in redirection ", e);
throw new IOException(e);
}
}
}

View File

@ -0,0 +1,30 @@
package eu.dnetlib.authentication.security.oidc;
import com.google.gson.JsonArray;
import com.nimbusds.jwt.JWT;
import eu.dnetlib.authentication.configuration.Properties;
import eu.dnetlib.authentication.utils.AuthoritiesMapper;
import org.mitre.openid.connect.client.OIDCAuthoritiesMapper;
import org.mitre.openid.connect.model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;
import java.util.Collection;
@Component
public class OpenAIREAuthoritiesMapper implements OIDCAuthoritiesMapper {
private final Properties properties;
@Autowired
OpenAIREAuthoritiesMapper(Properties properties) {
this.properties = properties;
}
@Override
public Collection<? extends GrantedAuthority> mapAuthorities(JWT jwtToken, UserInfo userInfo) {
JsonArray entitlements = userInfo.getSource().getAsJsonArray(properties.getAuthoritiesMapper());
return AuthoritiesMapper.map(entitlements);
}
}

View File

@ -0,0 +1,27 @@
package eu.dnetlib.authentication.security.oidc;
import eu.dnetlib.authentication.configuration.Properties;
import eu.dnetlib.authentication.utils.Redirect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Service
public class OpenAIRELogoutHandler implements LogoutHandler {
private final Properties properties;
@Autowired
public OpenAIRELogoutHandler(Properties properties) {
this.properties = properties;
}
@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
Redirect.setRedirect(request, properties);
}
}

View File

@ -0,0 +1,54 @@
package eu.dnetlib.authentication.security.oidc;
import eu.dnetlib.authentication.configuration.Properties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
@Configuration
public class OpenAIRELogoutSuccessHandler implements LogoutSuccessHandler {
private final Properties properties;
@Autowired
public OpenAIRELogoutSuccessHandler(Properties properties) {
this.properties = properties;
}
private String encodeValue(String value) throws UnsupportedEncodingException {
return URLEncoder.encode(value, StandardCharsets.UTF_8.toString());
}
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
if(properties.getOidc().getRedirect() == null) {
HttpSession session = request.getSession();
String redirect = (String) session.getAttribute("redirect");
session.removeAttribute("redirect");
if(redirect == null) {
redirect = properties.getRedirect();
}
session.invalidate();
response.sendRedirect(properties.getOidc().getLogout() + encodeValue(redirect));
} else {
StringBuilder sb = new StringBuilder(properties.getOidc().getIssuer());
if(properties.getKeycloak()) {
sb.append("/protocol/openid-connect/logout");
sb.append("?client_id=").append(properties.getOidc().getId());
sb.append("&post_logout_redirect_uri=").append(encodeValue(properties.getOidc().getRedirect()));
} else {
sb.append("/saml/logout");
}
response.sendRedirect(sb.toString());
}
}
}

View File

@ -0,0 +1,28 @@
package eu.dnetlib.authentication.security.oidc;
import org.mitre.openid.connect.client.UserInfoFetcher;
import org.mitre.openid.connect.model.PendingOIDCAuthenticationToken;
import org.mitre.openid.connect.model.UserInfo;
import org.springframework.stereotype.Component;
import java.nio.charset.StandardCharsets;
@Component
public class OpenAIREUserInfoFetcher extends UserInfoFetcher {
public OpenAIREUserInfoFetcher() {}
@Override
public UserInfo loadUserInfo(PendingOIDCAuthenticationToken token) {
UserInfo userInfo = super.loadUserInfo(token);
userInfo.setGivenName(encoder(userInfo.getGivenName()));
userInfo.setFamilyName(encoder(userInfo.getFamilyName()));
userInfo.setName(encoder(userInfo.getName()));
return userInfo;
}
private String encoder(String value) {
String decodedString = new String(value.getBytes(StandardCharsets.UTF_8));
return new String(decodedString.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
}
}

View File

@ -0,0 +1,20 @@
package eu.dnetlib.authentication.services;
import eu.dnetlib.authentication.entities.User;
import eu.dnetlib.authentication.exception.ResourceNotFoundException;
import org.mitre.openid.connect.model.OIDCAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
@Service
public class UserInfoService {
public User getUserInfo() throws ResourceNotFoundException {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if(authentication instanceof OIDCAuthenticationToken) {
return new User((OIDCAuthenticationToken) authentication);
}
throw new ResourceNotFoundException("No Session has been found");
}
}

View File

@ -0,0 +1,42 @@
package eu.dnetlib.authentication.utils;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import java.util.Collection;
import java.util.HashSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class AuthoritiesMapper {
private static final Logger logger = LogManager.getLogger(AuthoritiesMapper.class);
public static Collection<? extends GrantedAuthority> map(JsonArray entitlements) {
HashSet<SimpleGrantedAuthority> authorities = new HashSet<>();
String regex = "urn:geant:openaire[.]eu:group:([^:]*):?(.*)?:role=member#aai[.]openaire[.]eu";
for(JsonElement obj: entitlements) {
Matcher matcher = Pattern.compile(regex).matcher(obj.getAsString());
if (matcher.find()) {
StringBuilder sb = new StringBuilder();
if(matcher.group(1) != null && matcher.group(1).length() > 0) {
sb.append(matcher.group(1).replace("+-+", "_").replaceAll("[+.]", "_").toUpperCase());
}
if(matcher.group(2).length() > 0) {
sb.append("_");
if(matcher.group(2).equals("admins")) {
sb.append("MANAGER");
} else {
sb.append(matcher.group(2).toUpperCase());
}
}
authorities.add(new SimpleGrantedAuthority(sb.toString()));
}
}
return authorities;
}
}

View File

@ -0,0 +1,19 @@
package eu.dnetlib.authentication.utils;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class EntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
}
}

View File

@ -0,0 +1,25 @@
package eu.dnetlib.authentication.utils;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public class PropertyReader {
Set<String> scopes;
public PropertyReader(String property) {
if (!property.trim().isEmpty()){
scopes = new HashSet<>();
Collections.addAll(scopes, property.split(","));
}
}
public Set<String> getScopes() {
return scopes;
}
public void setScopes(Set<String> scopes) {
this.scopes = scopes;
}
}

View File

@ -0,0 +1,40 @@
package eu.dnetlib.authentication.utils;
import eu.dnetlib.authentication.configuration.Properties;
import org.apache.http.client.utils.URIBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.net.URISyntaxException;
import java.util.Enumeration;
public class Redirect {
private final static Logger logger = LogManager.getLogger(Redirect.class);
private static String getDomain(String url) throws URISyntaxException {
URIBuilder uriBuilder = new URIBuilder(url);
return uriBuilder.getHost();
}
public static void setRedirect(HttpServletRequest request, Properties properties) {
HttpSession session = request.getSession();
Enumeration<String> params = request.getParameterNames();
while (params.hasMoreElements()) {
String param = params.nextElement();
if(param.equalsIgnoreCase("redirect")) {
String redirect = request.getParameter(param);
try {
if(getDomain(redirect).endsWith(properties.getDomain())) {
session.setAttribute("redirect", redirect);
}
} catch (URISyntaxException e) {
logger.error(e.getMessage());
}
}
}
}
}

View File

@ -0,0 +1,16 @@
authentication.domain=di.uoa.gr
authentication.keycloak=false
authentication.oidc.issuer=https://aai.openaire.eu/oidc/
authentication.oidc.logout=https://aai.openaire.eu/proxy/saml2/idp/SingleLogoutService.php?ReturnTo=
authentication.oidc.home=http://mpagasas.di.uoa.gr:19080/login-service/openid_connect_login
authentication.oidc.scope=openid,profile,email,eduperson_entitlement
authentication.oidc.id=id
authentication.oidc.secret=secret
#authentication.oidc.redirect=http://mpagasas.di.uoa.gr:19080/login-service/redirect
authentication.session=openAIRESession
authentication.accessToken=AccessToken
authentication.redirect=http://mpagasas.di.uoa.gr:4600/reload
#authentication.authorities-mapper=eduperson_entitlement