diff --git a/src/main/java/de/rtuni/ms/as/JwtConfig.java b/src/main/java/de/rtuni/ms/as/JwtConfig.java deleted file mode 100644 index 9ecde7d16b2a2e883341489d9a2cc70573a35de0..0000000000000000000000000000000000000000 --- a/src/main/java/de/rtuni/ms/as/JwtConfig.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2019 (C) by Julian Horner. - * All Rights Reserved. - */ - -package de.rtuni.ms.as; - -import org.springframework.beans.factory.annotation.Value; - -/** - * Configuration class for json web token. - * - * @author Julian - * - */ -public class JwtConfig { - //---------------------------------------------------------------------------------------------- - - @Value("${security.jwt.uri:/auth/**}") - private String Uri; - - @Value("${security.jwt.header:Authorization}") - private String header; - - @Value("${security.jwt.prefix:Bearer}") - private String prefix; - - @Value("${security.jwt.expiration:#{24*60*60}}") - private int expiration; - - @Value("${security.jwt.secret:JwtSecretKey}") - private String secret; - - //---------------------------------------------------------------------------------------------- - - /** - * Get the uri. - * - * @return The uri - */ - public String getUri() { return Uri; } - - /** - * Get the header. - * - * @return The header - */ - public String getHeader() { return header; } - - /** - * Get the prefix. - * - * @return The prefix - */ - public String getPrefix() { return prefix; } - - /** - * Get the expiration. - * - * @return The expiration - */ - public int getExpiration() { return expiration; } - - /** - * Get the secret. - * - * @return The secret - */ - public String getSecret() { return secret; } - - //---------------------------------------------------------------------------------------------- -} diff --git a/src/main/java/de/rtuni/ms/as/JwtUsernameAndPasswordAuthenticationFilter.java b/src/main/java/de/rtuni/ms/as/JwtUsernameAndPasswordAuthenticationFilter.java deleted file mode 100644 index 4e9627fae371b730f96fa4e81e48fb2d779b117c..0000000000000000000000000000000000000000 --- a/src/main/java/de/rtuni/ms/as/JwtUsernameAndPasswordAuthenticationFilter.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2019 (C) by Julian Horner. - * All Rights Reserved. - */ - -package de.rtuni.ms.as; - -import java.io.IOException; -import java.util.Collections; -import java.util.Date; -import java.util.stream.Collectors; - -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; - -/** - * Filter class for json web token authentication of user name and password. - * - * @author Julian - */ -public class JwtUsernameAndPasswordAuthenticationFilter - extends UsernamePasswordAuthenticationFilter { - //---------------------------------------------------------------------------------------------- - - /** We use auth manager to validate the user credentials */ - private AuthenticationManager authManager; - - /** The configuration for the json web token. */ - private final JwtConfig jwtConfig; - - //---------------------------------------------------------------------------------------------- - - /** - * Creates an instance with the given <code>AuthenticationManager</code> and the given - * <code>JwtConfig</code>. - * - * @param authManager The stated manager - * @param jwtConfig The stated configuration for json web token - */ - public JwtUsernameAndPasswordAuthenticationFilter(AuthenticationManager authManager, - JwtConfig jwtConfig) { - this.authManager = authManager; - this.jwtConfig = jwtConfig; - - // By default, UsernamePasswordAuthenticationFilter listens to "/login" path. - // In our case, we use "/auth". So, we need to override the defaults. - this.setRequiresAuthenticationRequestMatcher( - new AntPathRequestMatcher(jwtConfig.getUri(), "POST")); - } - - //---------------------------------------------------------------------------------------------- - - /** - * {@inheritDoc} - */ - @Override - public Authentication attemptAuthentication(HttpServletRequest request, - HttpServletResponse response) throws AuthenticationException { - try { - // 1. Get credentials from request - UserCredentials creds = - new ObjectMapper().readValue(request.getInputStream(), UserCredentials.class); - // 2. Create auth object (contains credentials) which will be used by auth manager - UsernamePasswordAuthenticationToken authToken = - new UsernamePasswordAuthenticationToken( - creds.getUsername(), creds.getPassword(), Collections.emptyList()); - // 3. Authentication manager authenticate the user, and use - // UserDetailsServiceImpl::loadUserByUsername() method to load the user. - - return authManager.authenticate(authToken); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - //---------------------------------------------------------------------------------------------- - - /** - * Upon successful authentication, generate a token. The 'auth' passed to - * successfulAuthentication() is the current authenticated user. - * - * {@inheritDoc} - */ - @Override - protected void successfulAuthentication(HttpServletRequest request, - HttpServletResponse response, FilterChain chain, Authentication auth) - throws IOException, ServletException { - Long now = System.currentTimeMillis(); - String token = Jwts.builder().setSubject(auth.getName()) - // Convert to list of strings. This is important because it affects the way we - // get them back in the Gateway. - .claim("authorities", - auth.getAuthorities().stream().map(GrantedAuthority::getAuthority) - .collect(Collectors.toList())) - .setIssuedAt(new Date(now)) - .setExpiration(new Date(now + jwtConfig.getExpiration() * 1000)) // in milliseconds - .signWith(SignatureAlgorithm.HS512, jwtConfig.getSecret().getBytes()).compact(); - - // Add token to header - response.addHeader(jwtConfig.getHeader(), jwtConfig.getPrefix() + token); - } - - //---------------------------------------------------------------------------------------------- - - /** - * A (temporary) class just to represent the user credentials. - * - * @author Julian - * - */ - private static class UserCredentials { - private String username; - private String password; - - public String getUsername() { return username; } - - public void setUsername(final String value) { username = value; } - - public String getPassword() { return password; } - - public void setPassword(final String value) { password = value; } - - } - - //---------------------------------------------------------------------------------------------- -} diff --git a/src/main/java/de/rtuni/ms/as/SecurityConfiguration.java b/src/main/java/de/rtuni/ms/as/SecurityConfiguration.java deleted file mode 100644 index f7e97f08f1cb8de17da8205d72f964a12b6d4e68..0000000000000000000000000000000000000000 --- a/src/main/java/de/rtuni/ms/as/SecurityConfiguration.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2019 (C) by Julian Horner. - * All Rights Reserved. - */ - -package de.rtuni.ms.as; - -import javax.servlet.http.HttpServletResponse; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.http.HttpMethod; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -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.config.http.SessionCreationPolicy; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; - -/** - * Class that handles security configuration. - * - * @author Julian - * - */ -@EnableWebSecurity -public class SecurityConfiguration extends WebSecurityConfigurerAdapter { - //---------------------------------------------------------------------------------------------- - - /** A service that loads users from the database. */ - @Autowired - private UserDetailsService userDetailsService; - - /** The configuration for the json web token. */ - @Autowired - private JwtConfig jwtConfig; - - //---------------------------------------------------------------------------------------------- - - /** - * Overrides the default configuration. - */ - @Override - protected void configure(HttpSecurity http) throws Exception { - http.csrf().disable() - // make sure we use stateless session; session won't be used to store user's state. - .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() - // handle an authorized attempts - .exceptionHandling().authenticationEntryPoint( - (req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED)) - .and() - - /* - * Add a filter to validate user credentials and add token in the response header. - * - * What's the authenticationManager()? An object provided by WebSecurityConfigurerAdapter, - * used to authenticate the user passing user's credentials. The filter needs this - * authentication manager to authenticate the user. - */ - .addFilter( - new JwtUsernameAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig)) - .authorizeRequests() - // allow all POST requests - .antMatchers(HttpMethod.POST, jwtConfig.getUri()).permitAll() - // any other requests must be authenticated - .anyRequest().authenticated(); - } - - /** - * Spring has <code>UserDetailsService</code> interface, which can be overridden to provide our - * implementation for fetching user from database (or any other source). - * <p> - * The UserDetailsService object is used by the authentication manager to load the user - * from database. In addition, we need to define the password encoder also. So, authentication - * manager can compare and verify passwords. - */ - @Override - protected void configure(AuthenticationManagerBuilder auth) throws Exception { - auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); - } - - //---------------------------------------------------------------------------------------------- - - /** - * Get a new <code>JwtConfig</code>. - * - * @return The stated configuration - */ - @Bean - public JwtConfig jwtConfig() { return new JwtConfig(); } - - //---------------------------------------------------------------------------------------------- - - /** - * Get a new <code>BCryptPasswordEncoder</code>. - * - * @return The stated encoder - */ - @Bean - public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } - - //---------------------------------------------------------------------------------------------- -} diff --git a/src/main/java/de/rtuni/ms/as/UserDetailsServiceImpl.java b/src/main/java/de/rtuni/ms/as/UserDetailsServiceImpl.java deleted file mode 100644 index be6732fda23c3184e5046d78fb61d34cdc384392..0000000000000000000000000000000000000000 --- a/src/main/java/de/rtuni/ms/as/UserDetailsServiceImpl.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2019 (C) by Julian Horner. - * All Rights Reserved. - */ - -package de.rtuni.ms.as; - -import java.util.Arrays; -import java.util.List; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.stereotype.Service; - -/** - * Class that is able to load users. - * - * @author Julian - */ -@Service -public class UserDetailsServiceImpl implements UserDetailsService { - //---------------------------------------------------------------------------------------------- - - /** The password encoder. */ - @Autowired - private BCryptPasswordEncoder encoder; - - //---------------------------------------------------------------------------------------------- - - /** - * Loads a user by the given name. - * - * @param The stated name - */ - @Override - public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException { - // hard coding users. All passwords must be encoded. - final List<AppUser> users = Arrays.asList( - new AppUser(1, "julian", encoder.encode("12345"), "USER"), - new AppUser(2, "admin", encoder.encode("12345"), "ADMIN")); - - for (AppUser appUser : users) { - if (appUser.getUsername().equals(username)) { - /* - * Remember that Spring needs roles to be in this format: "ROLE_" + userRole - * (i.e."ROLE_ADMIN") - * So, we need to set it to that format, so we can verify and compare roles - * (i.e. hasRole("ADMIN")). - */ - List<GrantedAuthority> grantedAuthorities = - AuthorityUtils.commaSeparatedStringToAuthorityList( - "ROLE_" + appUser.getRole()); - - /* - * The "User" class is provided by Spring and represents a model class for user to - * be returned by UserDetailsService and used by authentication manager to verify - * and check use authentication. - */ - return new User(appUser.getUsername(), appUser.getPassword(), grantedAuthorities); - } - } - - // If user not found. Throw this exception. - throw new UsernameNotFoundException("Username: " + username + " not found"); - } - - //---------------------------------------------------------------------------------------------- - - /** - * A (temporary) class represent the user saved in the database. - * - * @author Julian - * - */ - private static class AppUser { - private Integer id; - private String username; - private String password; - private String role; - - public AppUser(final Integer id, final String username, final String password, - final String role) { - this.id = id; - this.username = username; - this.password = password; - this.role = role; - } - - public Integer getId() { return id; } - - public void setId(final Integer value) { id = value; } - - public String getUsername() { return username; } - - public void setUsername(final String value) { username = value; } - - public String getPassword() { return password; } - - public void setPassword(final String value) { password = value; } - - public String getRole() { return role; } - - public void setRole(final String value) { role = value; } - - } - - //---------------------------------------------------------------------------------------------- -} diff --git a/src/main/java/de/rtuni/ms/as/Application.java b/src/main/java/de/rtuni/ms/ds/Application.java similarity index 87% rename from src/main/java/de/rtuni/ms/as/Application.java rename to src/main/java/de/rtuni/ms/ds/Application.java index f024e1b8ffd0bdc448b68d7f6f46589643ea9b27..59f6bcd0fb4c180fc73f87ae3dd1cb3afa1b5437 100644 --- a/src/main/java/de/rtuni/ms/as/Application.java +++ b/src/main/java/de/rtuni/ms/ds/Application.java @@ -3,14 +3,14 @@ * All Rights Reserved. */ -package de.rtuni.ms.as; +package de.rtuni.ms.ds; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; /** - * Authentication service for microservice architecture. + * Dummy service for microservice architecture. * * @author Julian * diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 98429eedf14fa981799900be0a20b25f97d8b996..1b7b187896dc697bcea80a7514805d2a87c70fc4 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,10 +1,13 @@ # Spring properties spring: application: - name: auth-service # Identify this application + name: dummy-service # Identify this application + +# Map the error path to error template (for Thymeleaf) +error.path: /error # HTTP Server -server.port: 4444 # HTTP (Tomcat) port +server.port: 3333 # HTTP (Tomcat) port eureka: client: diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html new file mode 100644 index 0000000000000000000000000000000000000000..9b26a7209a63004c6808999ec264ba045970c2ba --- /dev/null +++ b/src/main/resources/templates/index.html @@ -0,0 +1,11 @@ +<!DOCTYPE HTML> +<html xmlns:th="http://www.thymeleaf.org"> + <head> + <title>Dummy page</title> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + </head> + <body> + <h1>Page without authentication</h1> + <a href="#" th:href="@{/securedPage}">geschützte Seite anfordern</a> + </body> +</html> \ No newline at end of file