Skip to content
Snippets Groups Projects
Commit 93135e75 authored by Julian Horner's avatar Julian Horner
Browse files

Correct files

parent 81abd23e
No related branches found
No related tags found
No related merge requests found
{
"ServiceId": "com.ibm.cloudoe.orion.client.deploy",
"Params": {
"Target": {
"Url": "https://api.eu-gb.cf.cloud.ibm.com",
"Org": "organisation one",
"Space": "dev"
},
"Name": "dummy-service",
"Instrumentation": {
"domain": "eu-gb.mybluemix.net",
"instances": "1"
}
},
"Path": "manifest.yml",
"Type": "Cloud Foundry"
}
\ No newline at end of file
pom.xml 0 → 100644
<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>
<groupId>de.rtuni.ms.as</groupId>
<artifactId>authentication-service</artifactId>
<version>1.0.0</version>
<packaging>war</packaging>
<name>authentication-service</name>
<description>Authentication service for microservice architecture</description>
<properties>
<java.version>1.8</java.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>de.rtuni.ms.as.Application</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package de.rtuni.ms.as;
/*
* Copyright 2019 (C) by Julian Horner.
* All Rights Reserved.
*/
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* Authentication service for microservice architecture.
*
* @author Julian
*
*/
@SpringBootApplication
@EnableEurekaClient
public class Application {
//---------------------------------------------------------------------------------------------
/**
* Starts the application.
*
* @param args The arguments
*/
public static void main(final String[] args) { SpringApplication.run(Application.class, args); }
//---------------------------------------------------------------------------------------------
}
package de.rtuni.ms.as;
/*
* Copyright 2019 (C) by Julian Horner.
* All Rights Reserved.
*/
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; }
//----------------------------------------------------------------------------------------------
}
package de.rtuni.ms.as;
/*
* Copyright 2019 (C) by Julian Horner.
* All Rights Reserved.
*/
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; }
}
//----------------------------------------------------------------------------------------------
}
package de.rtuni.ms.as;
/*
* Copyright 2019 (C) by Julian Horner.
* All Rights Reserved.
*/
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(); }
//----------------------------------------------------------------------------------------------
}
package de.rtuni.ms.as;
/*
* Copyright 2019 (C) by Julian Horner.
* All Rights Reserved.
*/
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; }
}
//----------------------------------------------------------------------------------------------
}
# Spring properties
spring:
application:
name: auth-service # Identify this application
# HTTP Server
server.port: 4444 # HTTP (Tomcat) port
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment