Skip to content

Commit

Permalink
added user security login
Browse files Browse the repository at this point in the history
  • Loading branch information
tsviz committed Jan 4, 2024
1 parent 99e4b43 commit ea74c31
Show file tree
Hide file tree
Showing 14 changed files with 376 additions and 28 deletions.
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ ENV DB_URL=jdbcConnectionString
ENV USER_NAME=postgres
ENV PASSWORD=password
ENV CHANGELOG_VERSION=master.xml
ENV SPRING_JPA_PROPERTIES_HIBERNATE_DEFAULT_SCHEMA=public
RUN mkdir workspace
WORKDIR /workspace/
COPY target/salesmanager-*-SNAPSHOT.jar .
Expand Down
38 changes: 26 additions & 12 deletions build_and_run_app_in_container.sh
Original file line number Diff line number Diff line change
@@ -1,23 +1,37 @@
# !/bin/bash
#!/bin/bash

# This script will build the app and run it in a docker container

# Function to perform housekeeping tasks
cleanup() {
echo "Performing cleanup..."
# Stop and remove the app container if it exists
docker stop app-test
docker rm app-test
# Stop and remove the postgresql container if it exists
docker stop postgres_container
docker rm postgres_container
# Remove image if exists
docker rmi myapp-img:v1
# Remove volume if exists
docker volume rm postgresql-data
}

# Trap the EXIT signal to perform cleanup
trap cleanup EXIT

# Getting local ip address from ifconfig
LOCAL_IP=$(ifconfig | grep 'inet ' | grep -Fv 127.0.0.1 | awk '{print $2}')
# To run a local containerized postgresql db, run the following command:
# docker run -d -p 5432:5432 --name postgres_container -e POSTGRES_PASSWORD=Password123 -v postgresql-data:/var/lib/postgresql/data postgres
# Stop and remove the app container if it exists
docker stop app-test
docker rm app-test
# Remove image if exists
docker rmi myapp-img:v1
# Run a postgresql container with a volume to persist data
docker run -d -p 5432:5432 --name postgres_container -e POSTGRES_PASSWORD=Password123 -v postgresql-data:/var/lib/postgresql/data postgres
# Run any previous migrations and tag the latest version with Liquibase
mvn liquibase:rollback -Dliquibase.rollbackCount=999 -Dliquibase.url=jdbc:postgresql://${LOCAL_IP}:5432/postgres -Dliquibase.username=postgres -Dliquibase.password=Password123 -Dliquibase.changeLogFile=db/changelog/changelog_version-3.3.xml
# jdbc:postgresql://hostname:5432/MY_TEST_DATABASE
mvn liquibase:tag -Dliquibase.tag=v3.2 -Dliquibase.url=jdbc:postgresql://${LOCAL_IP}:5432/postgres -Dliquibase.username=postgres -Dliquibase.password=Password123 -Dliquibase.changeLogFile=db/changelog/changelog_version-3.3.xml
# Build the app and create a docker image from local dockerfile
mvn clean package
docker build -t myapp-img:v1 .
docker run -e USER_NAME=postgres -e PASSWORD=Password123 -e CHANGELOG_VERSION=changelog_version-3.3.xml -e DB_URL=jdbc:postgresql://${LOCAL_IP}:5432/postgres -t -d -p 80:8086 --name app-test myapp-img:v1
docker run -d -e USER_NAME=postgres -e PASSWORD=Password123 -e CHANGELOG_VERSION=changelog_version-3.3.xml -e DB_URL=jdbc:postgresql://${LOCAL_IP}:5432/postgres -t -p 80:8086 --name app-test myapp-img:v1
docker ps -a
echo "Waiting for 10 seconds for the app to start"
sleep 10
# Print the logs of the app from the container
docker logs app-test
docker logs -f app-test
59 changes: 52 additions & 7 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,59 @@
<scope>runtime</scope>
</dependency>

<!-- <dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.6.1</version>
<scope>test</scope>
</dependency> -->
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.2.Final</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

</dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>

<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>


<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.13.0</version>
</dependency>

</dependencies>

<build>
<plugins>
Expand Down
51 changes: 45 additions & 6 deletions src/main/java/net/codejava/AppController.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,25 @@

import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import java.security.Principal;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;


@Controller
public class AppController {
Expand All @@ -21,6 +30,9 @@ public class AppController {
*/
@Autowired
private SalesDAO dao;

@Autowired
private AuthenticationManager authenticationManager;

@Value("${enableSearchFeature}")
private boolean enableSearchFeature;
Expand All @@ -30,11 +42,14 @@ public boolean getEnableSearchFeature() {
}

@RequestMapping("/")
public String viewHomePage(Model model) {
List<Sale> listSale = dao.list();
model.addAttribute("enableSearchFeature", enableSearchFeature);
model.addAttribute("listSale", listSale);
return "index";
public String viewHomePage(Model model , Principal principal) {
// if (principal != null) {
// User is logged in, add the data to the model
List<Sale> listSale = dao.list();
model.addAttribute("enableSearchFeature", enableSearchFeature);
model.addAttribute("listSale", listSale);
// }
return "index";
}

@RequestMapping("/new")
Expand All @@ -52,6 +67,30 @@ public String save(@ModelAttribute("sale") Sale sale) {
return "redirect:/";
}

@RequestMapping(value = "/login", method = RequestMethod.GET)
public String loginGet(Model model) {
return "login";
}

@RequestMapping(value = "/login", method = RequestMethod.POST)
public String loginPost(HttpServletRequest request, Model model) {
String username = request.getParameter("username");
String password = request.getParameter("password");

// Authenticate the user
Authentication auth = new UsernamePasswordAuthenticationToken(username, password);
try {
auth = authenticationManager.authenticate(auth);
SecurityContextHolder.getContext().setAuthentication(auth);
} catch (BadCredentialsException e) {
model.addAttribute("error", "Invalid username or password.");
return "login";
}

// User is authenticated, redirect to landing page
return "redirect:/";
}

@RequestMapping("/edit/{id}")
public ModelAndView showEditForm(@PathVariable(name = "id") int id) {
ModelAndView mav = new ModelAndView("edit_form");
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/net/codejava/EnableWebSecurity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package net.codejava;

public @interface EnableWebSecurity {

}
15 changes: 15 additions & 0 deletions src/main/java/net/codejava/PasswordEncoderConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package net.codejava;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;


@Configuration
public class PasswordEncoderConfig {

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
57 changes: 57 additions & 0 deletions src/main/java/net/codejava/SecurityConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package net.codejava;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.core.userdetails.UserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;


@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private UserDetailsService userDetailsService;

@Autowired
private PasswordEncoder passwordEncoder;

@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login").permitAll()
// .anyRequest().permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
// .loginPage("/login")
// .loginProcessingUrl("/login") // This should match the form action in your login.html file
.usernameParameter("username")
.passwordParameter("password")
.defaultSuccessUrl("/", true) // This is the URL to redirect to after a successful login
.successForwardUrl("/")
.failureUrl("/login?error=true")
.permitAll()
.and()
.logout()
.logoutUrl("/logout") // This is the URL to send the user to once they have logged out
.invalidateHttpSession(true)
.permitAll();
}

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}
}
49 changes: 49 additions & 0 deletions src/main/java/net/codejava/User.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package net.codejava;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "\"user\"")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String username;
private String password;

// getters and setters methods
// getter for id
public Long getId() {
return id;
}

// setter for id
public void setId(Long id) {
this.id = id;
}

// getter for username
public String getUsername() {
return username;
}

// setter for username
public void setUsername(String username) {
this.username = username;
}

// getter for password
public String getPassword() {
return password;
}

// setter for password{
public void setPassword(String password){
this.password = password;
}
}
43 changes: 43 additions & 0 deletions src/main/java/net/codejava/UserDetailsServiceImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package net.codejava;

import org.hibernate.exception.SQLGrammarException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

private static final Logger logger = LoggerFactory.getLogger(UserDetailsServiceImpl.class);

@Autowired
private UserRepository userRepository;

@Autowired
private PasswordEncoder passwordEncoder;

public void createUser(User user) {
user.setPassword(passwordEncoder.encode(user.getPassword()));
userRepository.save(user);
}

@Override
public UserDetails loadUserByUsername(String username) {
try {
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User not found with username: " + username);
}
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), new ArrayList<>());
} catch (SQLGrammarException e) {
logger.error("SQL error when trying to find user by username: " + username, e);
throw new RuntimeException("An error occurred while trying to find user by username: " + username);
}
}
}
6 changes: 6 additions & 0 deletions src/main/java/net/codejava/UserRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package net.codejava;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username);
}
Loading

0 comments on commit ea74c31

Please sign in to comment.