Thursday, June 22, 2023

Spring Security - Sample Spring Security application with default settings

 Let's create a Spring boot app adding dependencies of Web, Spring security, Lombok.

As you have added Spring security, it will be enabled with Spring security by default.

To enable User name and password, i have added user name password to application.properties

This is not recommended way, just to test and demo purposes. 

By adding username and password, you can add only one credential.


Below is the code

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>spring-security-javaTechie</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-security-javaTechie</name>
<description>spring-security-bezkoder</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</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-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>

</project>

Application.properties

Note:

when you add spring secirity dependecy, by default Spring secirity will be enabled.

If you want to add user name and password, you add that using appplication.properties file

But this is not recommended, but you can try


spring.security.user.name=Alex
spring.security.user.password=Pass1


Controller

package com.example.springsecurityjavaTechie.controller;

import com.example.springsecurityjavaTechie.model.Product;
import com.example.springsecurityjavaTechie.model.UserInfo;
import com.example.springsecurityjavaTechie.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/products")
public class ProductController {

@Autowired
private ProductService service;

@GetMapping("/welcome")
public String welcome() {
return "Welcome this endpoint is not secure";
}



@GetMapping("/all")

public List<Product> getAllTheProducts() {
return service.getProducts();
}

@GetMapping("/{id}")

public Product getProductById(@PathVariable int id) {
return service.getProduct(id);
}
}

 

Service

package com.example.springsecurityjavaTechie.service;

import com.example.springsecurityjavaTechie.model.Product;
import com.example.springsecurityjavaTechie.model.UserInfo;
import com.example.springsecurityjavaTechie.repository.UserInfoRepository;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Service
public class ProductService {

List<Product> productList = null;



@PostConstruct
public void loadProductsFromDB() {
productList = IntStream.rangeClosed(1, 100)
.mapToObj(i -> Product.builder()
.productId(i)
.name("product " + i)
.qty(new Random().nextInt(10))
.price(new Random().nextInt(5000)).build()
).collect(Collectors.toList());
}


public List<Product> getProducts() {
return productList;
}

public Product getProduct(int id) {
return productList.stream()
.filter(product -> product.getProductId() == id)
.findAny()
.orElseThrow(() -> new RuntimeException("product " + id + " not found"));
}



}


Repo

package com.example.springsecurityjavaTechie.repository;


import com.example.springsecurityjavaTechie.model.UserInfo;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface UserInfoRepository extends JpaRepository<UserInfo, Integer> {
Optional<UserInfo> findByName(String username);

}


Model classes

package com.example.springsecurityjavaTechie.model;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Product {

private int productId;
private String name;
private int qty;
private double price;
}


To test the application just open a browser and check your endpoints with your used ports

http://localhost:8500/products/welcome

Will ask user name and password.

Give the user name and password you have configured.

If you give a wrong details, it will say "Bad credentials"


http://localhost:8500/products/all


Friday, June 16, 2023

MS - Security - OAuth 2

 Few key points to remember

  • Protocol for token based authorization
  • Delegate access without sharing credentials. Grant client to perform certain actions on behalf of user
  • Technically, oAuth is not authenticating user. User needs to pre authenticated to receive an access token. ( note: most implement both together and most confused over the concept of authentication + authorization )
  • Can have 3rd party OAuth providers. eg: Google,Facebook, Github, your OAuth server


Key Items to Remember

Client

Authorization Server

Resource Owner

Resource Server


Key Words / Terms

  • Access Token - random string , human unreadable
  • Refresh Token - Same as Access Token which used to renew access when expired
  • Client-Id / Secret - Identify the app/client
  • Scope - Allowed permission
  • JWT - most used mechanism to pass information  between services. Support Encryption.


Grant Types

Authorization Code

Client Credentials

Implicit

Password

Device Code






Thursday, June 15, 2023

MS - chapter 3 - This application has no explicit mapping for /error, so you are seeing this as a fallback.

 You  may see below error

When you try default page, or click link in Eureka server {http://{yourHostname}:8203/actuator/info}, this will lead to error page.

Error

eg: http://{yourHostname}:8203/actuator/info

Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Thu Jun 15 08:12:28 IST 2023
There was an unexpected error (type=Not Found, status=404).
No message available



I have seen some have answered to solve this by adding simple controller for "/" mapping

package com.demo.micro.student.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HomeController {

@RequestMapping("/")
public String home(){
return "Hello World";
}
}
this won't actually solve the issue

Solution

add below property to application.properties

#Enable actuator and all
management.endpoints.web.exposure.include=*


As of Spring Boot 2.0.0.RELEASE the default prefix for all endpoints is /actuator So if you want to check the health of an application, you should go to /actuator/health

To make an actuator endpoint available via HTTP, it needs to be both enabled and exposed.

By default:

  • only the /health and /info endpoints are exposed.
  • all endpoints but /shutdown are enabled (only /health and /info are exposed)
Above property will enable all.

Wednesday, June 14, 2023

MS - chapter 3 - Register services with Eureka

 Tech Stack

Java 8, Maven, Springboot 3.10 , 

Scenario

Here we will register create web services with Eureka server


1. Add Eureka client dependency

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

Here if dependency cannot download add version under properties

<properties>
<java.version>17</java.version>
<spring-cloud.version>2022.0.3</spring-cloud.version>
</properties>

And the dependency Management to download

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>


2. Inject Eureka client dependency at main class - register service with Eureka server

Here you can set the name of the service also

@Autowired
@Lazy
private EurekaClient eurekaClient;

@Value("${spring.application.name}")
private String appName;


3. Register Service With Eureka server / Add service as a Eureka client

Add below properties

Note: My service name is "student"

spring.application.name=student
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/

4. You can start the client. Now your client will be registered with the Eureka Server.

Note: If you are using a database, make sure it is up and running

In here, we are using Mysql.

If it is not running you can start using command "mysqld --console"


Below is the Important Code base


Main Class

package com.demo.micro.student;

import com.netflix.discovery.EurekaClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Lazy;


@SpringBootApplication
public class StudentApplication {

@Autowired
@Lazy
private EurekaClient eurekaClient;

@Value("${spring.application.name}")
private String appName;
public static void main(String[] args) {
SpringApplication.run(StudentApplication.class, args);
}

}


application.properties for your reference

server.port=8203
spring.datasource.url=jdbc:mysql://localhost:3306/student_mgt
spring.datasource.username=root
spring.datasource.password=root

# for Spring Boot 2
# spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQL5InnoDBDialect
# for Spring Boot 3
spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQLDialect
spring.jpa.show-sql=false
spring.jpa.generate-ddl=true
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

spring.application.name=student
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/

References

https://cloud.spring.io/spring-cloud-netflix/multi/multi__service_discovery_eureka_clients.html

https://www.baeldung.com/spring-cloud-netflix-eureka

MS - chapter 2 - Create Eureka server

 Go to https://start.spring.io/

Add Eureka Server , dependency


Tech Stack

Java 8, Maven, Springboot 3.10 , 


1. Add @EnableEurekaServer   annotation at main class

2. add relavant properties to enable Eureka server

eureka.client.registerWithEureka = false
eureka.client.fetchRegistry = false
server.port = 8761

3. Run Main class and test Eureka server  http://localhost:8761/

Below is the  code

POM

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.demo.micro</groupId>
<artifactId>eureka-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka-server</name>
<description>Eureka server</description>
<properties>
<java.version>17</java.version>
<spring-cloud.version>2022.0.3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

application.Properties

eureka.client.registerWithEureka=false
eureka.client.fetchRegistry=false
server.port=8200


Main class


package com.demo.micro.eurekaserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {

public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}

}



MS - Springboot + Hibernate + Rest web service chapter 1

 Create a simple REST web service using springboot.

Use spring initializer   https://start.spring.io/

Dependencies

Web, JPA, database ( Mysql Connctor ) 

for your wish you can use, lombok, actuator, devtools

Webservice will include simple CRUD operation alias with REST POST,GET, PUT, GET

Tech Stack

Java 8, Maven, Springboot 3.10 , 


Sample code as below

POM file

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.demo.micro</groupId>
<artifactId>student</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>student</name>
<description>Student Service</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>


Application properties

server.port=8203
spring.datasource.url=jdbc:mysql://localhost:3306/student_mgt
spring.datasource.username=root
spring.datasource.password=root

# for Spring Boot 2
# spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQL5InnoDBDialect
# for Spring Boot 3
spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQLDialect
spring.jpa.show-sql=false
spring.jpa.generate-ddl=true
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl



Code base Structure

com.demo.micro.student

controller --> will include REST API

model --> model classes

repository --> repo file, db connection

service --> service classes

MainApllication --> StudentApplication with @SpringBootApplication


Controller

package com.demo.micro.student.controller;

import com.demo.micro.student.model.Student;
import com.demo.micro.student.service.StudentServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping("/students")
public class StudentController {

@Autowired
StudentServiceImpl studentService;

@GetMapping("")
public ResponseEntity<List<Student>> list() {
return new ResponseEntity<List<Student>>(studentService.list(), HttpStatus.OK);
}

@PostMapping("")
public ResponseEntity<Student> resgiterStudent(@RequestBody Student student) {
try {
Student st = studentService.createStudent(student);
return new ResponseEntity<>(st, HttpStatus.CREATED);
} catch (Exception e) {
return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
}
}

@PutMapping("")
public ResponseEntity<Student> updateStudent(@RequestBody Student student) {
return new ResponseEntity<>(studentService.createStudent(student), HttpStatus.OK);
}

@PutMapping("/{id}")
public ResponseEntity<Student> updateStudent(@PathVariable("id") int id, @RequestBody Student student) {
Optional<Student> st = studentService.findById(id);
if (st.isPresent()) {
// set details for student
return new ResponseEntity<>(studentService.createStudent(student), HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}

/**
* Don't do this. We normally makes a soft delete -
* 1. update flag/property as deleted. But flag is redundant field
* 2. use date/time option. nullable date time or default old time.
*
* @param student
* @return
*/
@DeleteMapping("")
public ResponseEntity<Student> deleteStudent(@RequestBody Student student) {
studentService.deleteStudent(student);
return new ResponseEntity<>(null, HttpStatus.ACCEPTED);
}
}


Model

package com.demo.micro.student.model;

import jakarta.persistence.*;
import lombok.Data;

/**
* Student details.
*/
@Entity
@Table(name = "student")
@Data
public class Student {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "student_id")
private int studentId;

/**
* First name of the student.
*/
@Column(name = "first_name")
private String firstName;

/**
* Last name of the student.
*/
@Column(name = "last_name")
private String lastName;


}

Repository

package com.demo.micro.student.repository;

import com.demo.micro.student.model.Student;
import org.springframework.data.jpa.repository.JpaRepository;

public interface StudentRepository extends JpaRepository<Student,Integer> {
}


Service classes - Interface and Impl

package com.demo.micro.student.service;

import com.demo.micro.student.model.Student;

import java.util.List;
import java.util.Optional;

/**
*
*/
public interface StudentService {

/**
* Returns a list of {@link Student}s.
* @return list of {@link Student}
*/
List<Student> list();
Student createStudent(Student student);

Optional<Student> findById(int studentId);

void deleteStudent(Student student);
}


package com.demo.micro.student.service;

import com.demo.micro.student.model.Student;
import com.demo.micro.student.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
public class StudentServiceImpl implements StudentService {

@Autowired
StudentRepository studentRepository;

/**
* List all the {@link Student}
*
* @return
*/
@Override
public List<Student> list() {
return studentRepository.findAll();
}

/**
* Create a new record of {@link Student}.
*
* @param student
* @return
*/
@Override
public Student createStudent(Student student) {
return studentRepository.save(student);
}

@Override
public Optional<Student> findById(int studentId) {
return studentRepository.findById(studentId);
}

public void deleteStudent(Student student) {
studentRepository.delete(student);
}

}


Important : Note that we put @Srvivie at Impl class, not Interface


Main class

package com.demo.micro.student;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class StudentApplication {

public static void main(String[] args) {
SpringApplication.run(StudentApplication.class, args);
}

}






Friday, May 26, 2023

Windows Process useful commands

 

windows find port usage

netstat -aon | findstr<port_number>

eg: netstat -ano | findstr 8081


windows check details of process id

tasklist /fi "pid eq <process id>"

eg: tasklist /fi "pid eq 4716"


Kill Process forcefully

taskkill /im myprocess.exe /f

The "/f" is for "force". If you know the PID, then you can specify that, as in:

taskkill /pid 4716 /f