Java Design patterns
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
package javadevjournal.design.creational.abstractfactory;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public abstract class AbstractFactory {
|
||||
abstract Shape getShape(String shapeType) ;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package javadevjournal.design.creational.abstractfactory;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class AbstractFactoryDemo {
|
||||
public static void main(String[] args) {
|
||||
/* get shape factory */
|
||||
AbstractFactory shapeFactory = FactoryOfFactory.getFactory(false);
|
||||
/* get an object of Shape Rectangle */
|
||||
Shape shape1 = shapeFactory.getShape("RECTANGLE");
|
||||
/* call draw method of Shape Rectangle */
|
||||
shape1.drawShape();
|
||||
/* get an object of Shape Square */
|
||||
Shape shape2 = shapeFactory.getShape("SQUARE");
|
||||
/* call draw method of Shape Square */
|
||||
shape2.drawShape();
|
||||
/* get rounded shape factory */
|
||||
AbstractFactory roundShapeFactory = FactoryOfFactory.getFactory(true);
|
||||
/* get an object of Shape Rectangle */
|
||||
Shape shape3 = roundShapeFactory.getShape("RECTANGLE");
|
||||
/* call draw method of Shape Rectangle */
|
||||
shape3.drawShape();
|
||||
/* get an object of Shape Square */
|
||||
Shape shape4 = roundShapeFactory.getShape("SQUARE");
|
||||
/* call draw method of Shape Square */
|
||||
shape4.drawShape();
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package javadevjournal.design.creational.abstractfactory;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class FactoryOfFactory {
|
||||
public static AbstractFactory getFactory(boolean rounded){
|
||||
if(rounded){
|
||||
return new RoundedShapeFactory();
|
||||
}else{
|
||||
return new ShapeFactory();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package javadevjournal.design.creational.abstractfactory;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class Rectangle implements Shape {
|
||||
@Override
|
||||
public void drawShape() {
|
||||
System.out.println("Inside Rectangle::draw() method.");
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package javadevjournal.design.creational.abstractfactory;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class RoundedRectangle implements Shape {
|
||||
@Override
|
||||
public void drawShape() {
|
||||
System.out.println("Inside RoundedRectangle::draw() method.");
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package javadevjournal.design.creational.abstractfactory;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class RoundedShapeFactory extends AbstractFactory {
|
||||
@Override
|
||||
public Shape getShape(String shapeType){
|
||||
if(shapeType.equalsIgnoreCase("RECTANGLE")){
|
||||
return new RoundedRectangle();
|
||||
}else if(shapeType.equalsIgnoreCase("SQUARE")){
|
||||
return new RoundedSquare();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package javadevjournal.design.creational.abstractfactory;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class RoundedSquare implements Shape {
|
||||
@Override
|
||||
public void drawShape() {
|
||||
System.out.println("Inside RoundedSquare::draw() method.");
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package javadevjournal.design.creational.abstractfactory;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public interface Shape {
|
||||
void drawShape();
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package javadevjournal.design.creational.abstractfactory;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class ShapeFactory extends AbstractFactory {
|
||||
@Override
|
||||
public Shape getShape(String shapeType){
|
||||
if(shapeType.equalsIgnoreCase("RECTANGLE")){
|
||||
return new Rectangle();
|
||||
}else if(shapeType.equalsIgnoreCase("SQUARE")){
|
||||
return new Square();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package javadevjournal.design.creational.abstractfactory;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class Square implements Shape {
|
||||
@Override
|
||||
public void drawShape() {
|
||||
System.out.println("Inside Square::draw() method.");
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package javadevjournal.design.creational.abstractfactory.example2;
|
||||
|
||||
/**
|
||||
* Abstract Factory - Factory of Factories
|
||||
*/
|
||||
public abstract class AbstractFactory{
|
||||
abstract IMobile getMobile(String mobileModel) ;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package javadevjournal.design.creational.abstractfactory.example2;
|
||||
|
||||
/**
|
||||
* Client Class
|
||||
*/
|
||||
public class AbstractFactoryPatternDemo{
|
||||
public static void main(String[] args){
|
||||
AbstractFactory abstractFactory1 = MpbileFactoryProducer.getFactory(false);
|
||||
IMobile onePlus = abstractFactory1.getMobile("Oneplus");
|
||||
onePlus.brandName();
|
||||
IMobile sony = abstractFactory1.getMobile("Sony");
|
||||
sony.brandName();
|
||||
IMobile lava = abstractFactory1.getMobile("Lava");
|
||||
lava.brandName();
|
||||
AbstractFactory abstractFactory2 = MpbileFactoryProducer.getFactory(true);
|
||||
IMobile iphone = abstractFactory2.getMobile("iphone");
|
||||
iphone.brandName();
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package javadevjournal.design.creational.abstractfactory.example2;
|
||||
|
||||
/**
|
||||
* Android Mobile Factory
|
||||
*/
|
||||
public class AndroidMobileFactory extends AbstractFactory {
|
||||
@Override
|
||||
public IMobile getMobile(String mobileModel){
|
||||
if(mobileModel.equalsIgnoreCase("Oneplus")){
|
||||
return new OnePlus();
|
||||
}else if(mobileModel.equalsIgnoreCase("Sony")){
|
||||
return new Sony();
|
||||
}else if(mobileModel.equalsIgnoreCase("Lava")){
|
||||
return new Lava();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package javadevjournal.design.creational.abstractfactory.example2;
|
||||
|
||||
/**
|
||||
* Apple Mobile Factory
|
||||
*/
|
||||
public class AppleMobileFactory extends AbstractFactory{
|
||||
@Override
|
||||
public IMobile getMobile(String mobileModel){
|
||||
if(mobileModel.equalsIgnoreCase("iphone")){
|
||||
return new Iphone();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package javadevjournal.design.creational.abstractfactory.example2;
|
||||
|
||||
/**
|
||||
* Mobile
|
||||
*/
|
||||
public interface IMobile {
|
||||
void brandName();
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package javadevjournal.design.creational.abstractfactory.example2;
|
||||
|
||||
/**
|
||||
* Iphone Mobile
|
||||
*/
|
||||
public class Iphone implements IMobile {
|
||||
@Override
|
||||
public void brandName() {
|
||||
System.out.println("The brand name is Iphone");
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package javadevjournal.design.creational.abstractfactory.example2;
|
||||
|
||||
/**
|
||||
* Nokia Mobile Concrete Class
|
||||
*/
|
||||
public class Lava implements IMobile {
|
||||
@Override
|
||||
public void brandName() {
|
||||
System.out.println("The brand name is Lava");
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package javadevjournal.design.creational.abstractfactory.example2;
|
||||
|
||||
/**
|
||||
* Factory Producer
|
||||
*/
|
||||
public class MpbileFactoryProducer {
|
||||
public static AbstractFactory getFactory(boolean isApple){
|
||||
if(isApple){
|
||||
return new AppleMobileFactory();
|
||||
}else{
|
||||
return new AndroidMobileFactory();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package javadevjournal.design.creational.abstractfactory.example2;
|
||||
|
||||
/**
|
||||
* OnePlus Mobile
|
||||
*/
|
||||
public class OnePlus implements IMobile {
|
||||
@Override
|
||||
public void brandName() {
|
||||
System.out.println("The brand name is OnePlus");
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package javadevjournal.design.creational.abstractfactory.example2;
|
||||
|
||||
/**
|
||||
* Sony Mobile
|
||||
*/
|
||||
public class Sony implements IMobile {
|
||||
@Override
|
||||
public void brandName() {
|
||||
System.out.println("The brand name is Sony");
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package javadevjournal.design.creational.builder;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
* Builder Pattern Client Class
|
||||
* Create Computer object with mandatory and optional properties
|
||||
*/
|
||||
public class BuilderPatternDemo {
|
||||
public static void main(String[] args) {
|
||||
|
||||
Computer model1 = new Computer.ComputerBuilder(
|
||||
"1 TB", "16 GB","15.6").setBluetoothEnabled(true)
|
||||
.setGraphicsCardEnabled(true).setTouchScreenEnabled(true).setWebCamEnabled(true).build();
|
||||
System.out.println("model1: " + model1.toString());
|
||||
|
||||
Computer model2 = new Computer.ComputerBuilder(
|
||||
"256 GB", "8 GB","14.6").setBluetoothEnabled(true)
|
||||
.setGraphicsCardEnabled(true).build();
|
||||
System.out.println("model2: "+model2.toString());
|
||||
|
||||
|
||||
Computer model3 = new Computer.ComputerBuilder(
|
||||
"128 GB", "4 GB","13.6").build();
|
||||
System.out.println("model3: "+model3.toString());
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
package javadevjournal.design.creational.builder;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
* Product Class
|
||||
* Builder Pattern Class
|
||||
*/
|
||||
public class Computer {
|
||||
//required parameters
|
||||
private String HDD;
|
||||
private String RAM;
|
||||
private String screenSize;
|
||||
|
||||
//optional parameters
|
||||
private boolean isGraphicsCardEnabled;
|
||||
private boolean isBluetoothEnabled;
|
||||
private boolean isWebCamEnabled;
|
||||
private boolean isTouchScreenEnabled;
|
||||
|
||||
public String getHDD() {
|
||||
return HDD;
|
||||
}
|
||||
|
||||
public String getRAM() {
|
||||
return RAM;
|
||||
}
|
||||
|
||||
public String getScreenSize() {
|
||||
return screenSize;
|
||||
}
|
||||
|
||||
public boolean isGraphicsCardEnabled() {
|
||||
return isGraphicsCardEnabled;
|
||||
}
|
||||
|
||||
public boolean isBluetoothEnabled() {
|
||||
return isBluetoothEnabled;
|
||||
}
|
||||
|
||||
public boolean isWebCamEnabled() {
|
||||
return isWebCamEnabled;
|
||||
}
|
||||
|
||||
public boolean isTouchScreenEnabled() {
|
||||
return isTouchScreenEnabled;
|
||||
}
|
||||
|
||||
private Computer(ComputerBuilder builder) {
|
||||
this.HDD=builder.HDD;
|
||||
this.RAM=builder.RAM;
|
||||
this.screenSize=builder.screenSize;
|
||||
this.isGraphicsCardEnabled=builder.isGraphicsCardEnabled;
|
||||
this.isBluetoothEnabled=builder.isBluetoothEnabled;
|
||||
this.isTouchScreenEnabled=builder.isTouchScreenEnabled;
|
||||
this.isWebCamEnabled=builder.isWebCamEnabled;
|
||||
this.isWebCamEnabled=builder.isWebCamEnabled;
|
||||
}
|
||||
|
||||
//Builder Class
|
||||
public static class ComputerBuilder{
|
||||
|
||||
// required parameters
|
||||
private String HDD;
|
||||
private String RAM;
|
||||
private String screenSize;
|
||||
|
||||
// optional parameters
|
||||
private boolean isGraphicsCardEnabled;
|
||||
private boolean isBluetoothEnabled;
|
||||
private boolean isWebCamEnabled;
|
||||
private boolean isTouchScreenEnabled;
|
||||
|
||||
public ComputerBuilder(String hdd, String ram, String screenSize){
|
||||
this.HDD=hdd;
|
||||
this.RAM=ram;
|
||||
this.screenSize=screenSize;
|
||||
}
|
||||
|
||||
public ComputerBuilder setGraphicsCardEnabled(boolean isGraphicsCardEnabled) {
|
||||
this.isGraphicsCardEnabled = isGraphicsCardEnabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ComputerBuilder setBluetoothEnabled(boolean isBluetoothEnabled) {
|
||||
this.isBluetoothEnabled = isBluetoothEnabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ComputerBuilder setWebCamEnabled(boolean webCamEnabled) {
|
||||
isWebCamEnabled = webCamEnabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ComputerBuilder setTouchScreenEnabled(boolean touchScreenEnabled) {
|
||||
isTouchScreenEnabled = touchScreenEnabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Computer build(){
|
||||
return new Computer(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Computer{" +
|
||||
"HDD='" + HDD + '\'' +
|
||||
", RAM='" + RAM + '\'' +
|
||||
", screenSize='" + screenSize + '\'' +
|
||||
", isGraphicsCardEnabled=" + isGraphicsCardEnabled +
|
||||
", isBluetoothEnabled=" + isBluetoothEnabled +
|
||||
", isWebCamEnabled=" + isWebCamEnabled +
|
||||
", isTouchScreenEnabled=" + isTouchScreenEnabled +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package javadevjournal.design.creational.factory;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class Circle implements Shape {
|
||||
@Override
|
||||
public void drawShape() {
|
||||
System.out.println("Inside Circle::drawShape() method.");
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package javadevjournal.design.creational.factory;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
* Factory Pattern Demo
|
||||
*/
|
||||
public class FactoryPatternDemo {
|
||||
public static void main(String[] args) {
|
||||
ShapeFactory shapeFactory = new ShapeFactory();
|
||||
|
||||
/* get an object of Circle Class and call its drawShape method. */
|
||||
Shape shape1 = shapeFactory.getShape("CIRCLE");
|
||||
shape1.drawShape();
|
||||
|
||||
/* get an object of Rectangle Class and call its drawShape method. */
|
||||
Shape shape2 = shapeFactory.getShape("RECTANGLE");
|
||||
shape2.drawShape();
|
||||
|
||||
/* get an object of Square Class and call its drawShape method. */
|
||||
Shape shape3 = shapeFactory.getShape("SQUARE");
|
||||
shape3.drawShape();
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package javadevjournal.design.creational.factory;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class Rectangle implements Shape {
|
||||
@Override
|
||||
public void drawShape() {
|
||||
System.out.println("Inside Rectangle::drawShape() method.");
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package javadevjournal.design.creational.factory;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public interface Shape {
|
||||
void drawShape();
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package javadevjournal.design.creational.factory;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
* Factory Pattern Implementation here
|
||||
*/
|
||||
public class ShapeFactory {
|
||||
/**
|
||||
* get the shapeType from caller and decide the correct implementation class
|
||||
* @param shapeType
|
||||
* @return
|
||||
*/
|
||||
public Shape getShape(String shapeType){
|
||||
if(shapeType == null){
|
||||
return null;
|
||||
}
|
||||
if(shapeType.equalsIgnoreCase("CIRCLE")){
|
||||
return new Circle();
|
||||
|
||||
} else if(shapeType.equalsIgnoreCase("RECTANGLE")){
|
||||
return new Rectangle();
|
||||
|
||||
} else if(shapeType.equalsIgnoreCase("SQUARE")){
|
||||
return new Square();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package javadevjournal.design.creational.factory;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class Square implements Shape {
|
||||
@Override
|
||||
public void drawShape() {
|
||||
System.out.println("Inside Square::drawShape() method.");
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package javadevjournal.design.creational.factory.banking;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public interface BankAccount {
|
||||
public void registerAccount();
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package javadevjournal.design.creational.factory.banking;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class BankAccountFactory {
|
||||
public BankAccount createAccount(String type){
|
||||
BankAccount bankAccount = null;
|
||||
if (type.equals("P")){
|
||||
bankAccount = new PersonalAccount();
|
||||
} else if (type.equals("B")){
|
||||
bankAccount = new BusinessAccount();
|
||||
} else if (type.equals("C")){
|
||||
bankAccount = new CheckingAccount();
|
||||
} else {
|
||||
System.out.println("Invalid type");
|
||||
}
|
||||
return bankAccount;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package javadevjournal.design.creational.factory.banking;
|
||||
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class Branch {
|
||||
public static void main(String[] args) {
|
||||
BankAccount bankAccount = null;
|
||||
BankAccountFactory bankAccountFactory = new BankAccountFactory();
|
||||
Scanner in = new Scanner(System.in);
|
||||
System.out.println("Please enter\n" +
|
||||
" P for Personal account\n" +
|
||||
" B for Business account\n" +
|
||||
" C for Checking account\n" +
|
||||
"----------------------------");
|
||||
String accountType = in.nextLine();
|
||||
bankAccount = bankAccountFactory.createAccount(accountType);
|
||||
bankAccount.registerAccount();;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package javadevjournal.design.creational.factory.banking;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class BusinessAccount implements BankAccount {
|
||||
@Override
|
||||
public void registerAccount() {
|
||||
System.out.println("Creating a business account");
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package javadevjournal.design.creational.factory.banking;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class CheckingAccount implements BankAccount{
|
||||
@Override
|
||||
public void registerAccount() {
|
||||
System.out.println("Creating a checking account");
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package javadevjournal.design.creational.factory.banking;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class PersonalAccount implements BankAccount{
|
||||
@Override
|
||||
public void registerAccount() {
|
||||
System.out.println("Creating a personal account");
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package javadevjournal.design.creational.singleton;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class Singleton {
|
||||
|
||||
/* private instance variable */
|
||||
private static Singleton instance = new Singleton();
|
||||
|
||||
/* private constructor */
|
||||
private Singleton(){}
|
||||
|
||||
/* returns the same object */
|
||||
public static Singleton getInstance(){
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package javadevjournal.design.creational.singleton;
|
||||
|
||||
public class SingletonMultiThreaded {
|
||||
|
||||
/* private instance variable */
|
||||
private static volatile SingletonMultiThreaded INSTANCE;
|
||||
|
||||
/* private constructor */
|
||||
private SingletonMultiThreaded() { }
|
||||
|
||||
public static SingletonMultiThreaded getInstance() {
|
||||
/* double-checking lock */
|
||||
if(null == INSTANCE){
|
||||
/* synchronized block */
|
||||
synchronized (SingletonMultiThreaded.class) {
|
||||
if(null == INSTANCE){
|
||||
INSTANCE = new SingletonMultiThreaded();
|
||||
}
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package javadevjournal.design.creational.singleton;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class SingletonPatternDemo {
|
||||
public static void main(String[] args) {
|
||||
/* Let's create 3 objects and see their hashcode and they will be same. */
|
||||
System.out.println("in single threaded environment");
|
||||
Singleton singleton1 = Singleton.getInstance();
|
||||
Singleton singleton2 = Singleton.getInstance();
|
||||
Singleton singleton3 = Singleton.getInstance();
|
||||
System.out.println(singleton1.hashCode() +" "+ singleton2.hashCode() +" "+ singleton3.hashCode());
|
||||
|
||||
System.out.println("in multi threaded environment");
|
||||
Thread1 t1 = new Thread1();
|
||||
t1.run();
|
||||
Thread2 t2 = new Thread2();
|
||||
t2.run();
|
||||
Thread3 t3 = new Thread3();
|
||||
t3.run();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package javadevjournal.design.creational.singleton;
|
||||
|
||||
public class Thread1 implements Runnable{
|
||||
@Override
|
||||
public void run() {
|
||||
SingletonMultiThreaded singletonMultiThreaded = SingletonMultiThreaded.getInstance();
|
||||
System.out.print(singletonMultiThreaded.hashCode() + " ");
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package javadevjournal.design.creational.singleton;
|
||||
|
||||
public class Thread2 implements Runnable{
|
||||
@Override
|
||||
public void run() {
|
||||
SingletonMultiThreaded singletonMultiThreaded = SingletonMultiThreaded.getInstance();
|
||||
System.out.print(singletonMultiThreaded.hashCode() + " ");
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package javadevjournal.design.creational.singleton;
|
||||
|
||||
public class Thread3 implements Runnable{
|
||||
@Override
|
||||
public void run() {
|
||||
SingletonMultiThreaded singletonMultiThreaded = SingletonMultiThreaded.getInstance();
|
||||
System.out.println(singletonMultiThreaded.hashCode());
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package javadevjournal.design.creational.singleton.breakit;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class BreakSingletonUsingReflection {
|
||||
public static void main(String[] args) {
|
||||
Singleton singleton1 = Singleton.instance;
|
||||
Singleton singleton2 = null;
|
||||
try {
|
||||
Constructor[] constructors =
|
||||
Singleton.class.getDeclaredConstructors();
|
||||
for (Constructor constructor : constructors) {
|
||||
// Below code will destroy the singleton pattern
|
||||
constructor.setAccessible(true);
|
||||
singleton2 = (Singleton) constructor.newInstance();
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println("instance1.hashCode(): " + singleton1.hashCode());
|
||||
System.out.println("instance2.hashCode(): " + singleton2.hashCode());
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package javadevjournal.design.creational.singleton.breakit;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
class Singleton{
|
||||
public static Singleton instance = new Singleton();
|
||||
private Singleton() {
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package javadevjournal.design.structural.adapter;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class AdapterPatternDemo {
|
||||
public static void main(String[] args) {
|
||||
AudioPlayer audioPlayer = new AudioPlayer();
|
||||
audioPlayer.playMusic("mp3", "song1.mp3");
|
||||
audioPlayer.playMusic("mp4", "song2.mp4");
|
||||
audioPlayer.playMusic("vlc", "song3.vlc");
|
||||
audioPlayer.playMusic("xyz", "song4.avi");
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package javadevjournal.design.structural.adapter;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public interface AdvancedMediaPlayer {
|
||||
void playVlcPlayer(String fileName);
|
||||
void playMp4Player(String fileName);
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package javadevjournal.design.structural.adapter;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class AudioPlayer implements MediaPlayer {
|
||||
private MediaAdapter mediaAdapter;
|
||||
@Override
|
||||
public void playMusic(String audioType, String fileName) {
|
||||
//the mp3 format is supported by AudioPlayer itself and it doesn't need adapter here.
|
||||
if(audioType.equalsIgnoreCase("mp3")){
|
||||
System.out.println("Playing mp3 file: " + fileName);
|
||||
}
|
||||
//to support other formats, we will need the MediaAdapter
|
||||
else if(audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")){
|
||||
mediaAdapter = new MediaAdapter(audioType);
|
||||
mediaAdapter.playMusic(audioType, fileName);
|
||||
}else{
|
||||
System.out.println("The given format: " + audioType + " is not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package javadevjournal.design.structural.adapter;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class MediaAdapter implements MediaPlayer {
|
||||
|
||||
public static final String VLC = "vlc";
|
||||
public static final String MP_4 = "mp4";
|
||||
|
||||
private AdvancedMediaPlayer advancedMusicPlayer;
|
||||
public MediaAdapter(String audioType){
|
||||
if(audioType.equalsIgnoreCase(VLC) ){
|
||||
advancedMusicPlayer = new VlcMusicPlayer();
|
||||
}else if (audioType.equalsIgnoreCase(MP_4)){
|
||||
advancedMusicPlayer = new Mp4MusicPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playMusic(String audioType, String fileName) {
|
||||
if(audioType.equalsIgnoreCase(VLC)){
|
||||
advancedMusicPlayer.playVlcPlayer(fileName);
|
||||
}else if(audioType.equalsIgnoreCase(MP_4)){
|
||||
advancedMusicPlayer.playMp4Player(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package javadevjournal.design.structural.adapter;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public interface MediaPlayer{
|
||||
void playMusic(String audioType, String fileName);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package javadevjournal.design.structural.adapter;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class Mp4MusicPlayer implements AdvancedMediaPlayer{
|
||||
|
||||
@Override
|
||||
public void playVlcPlayer(String fileName) {
|
||||
//do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playMp4Player(String fileName) {
|
||||
System.out.println("Playing mp4 file: "+ fileName);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package javadevjournal.design.structural.adapter;
|
||||
|
||||
/**
|
||||
* @author Kunwar
|
||||
*/
|
||||
public class VlcMusicPlayer implements AdvancedMediaPlayer{
|
||||
@Override
|
||||
public void playVlcPlayer(String fileName){
|
||||
System.out.println("Playing vlc file: "+ fileName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playMp4Player(String fileName) {
|
||||
//do nothing
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package javadevjournal.ds.avl;
|
||||
|
||||
class AVLNode{
|
||||
|
||||
AVLNode left, right;
|
||||
int data;
|
||||
int height;
|
||||
|
||||
public AVLNode(){
|
||||
left = null;
|
||||
right = null;
|
||||
data = 0;
|
||||
height = 0;
|
||||
}
|
||||
|
||||
public AVLNode(int n){
|
||||
left = null;
|
||||
right = null;
|
||||
data = n;
|
||||
height = 0;
|
||||
}
|
||||
}
|
||||
@@ -1,195 +0,0 @@
|
||||
package javadevjournal.ds.avl;
|
||||
|
||||
class AVLTree{
|
||||
private AVLNode root;
|
||||
public AVLTree(){
|
||||
root = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param avlNode
|
||||
* @return
|
||||
*/
|
||||
private int height(AVLNode avlNode ){
|
||||
return avlNode == null ? -1 : avlNode.height;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param lHeight
|
||||
* @param rHeight
|
||||
* @return
|
||||
*/
|
||||
private int max(int lHeight, int rHeight){
|
||||
return lHeight > rHeight ? lHeight : rHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
public void insert(int data){
|
||||
root = insert(data, root);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param data
|
||||
* @param avlNode
|
||||
* @return
|
||||
*/
|
||||
private AVLNode insert(int data, AVLNode avlNode)
|
||||
{
|
||||
if (avlNode == null)
|
||||
avlNode = new AVLNode(data);
|
||||
else if (data < avlNode.data){
|
||||
avlNode.left = insert( data, avlNode.left );
|
||||
if( height( avlNode.left ) - height( avlNode.right ) == 2 )
|
||||
if( data < avlNode.left.data )
|
||||
avlNode = leftRotation( avlNode );
|
||||
else
|
||||
avlNode = leftRightRotation( avlNode );
|
||||
}
|
||||
else if( data > avlNode.data ){
|
||||
avlNode.right = insert( data, avlNode.right );
|
||||
if( height( avlNode.right ) - height( avlNode.left ) == 2 )
|
||||
if( data > avlNode.right.data)
|
||||
avlNode = rightRotation( avlNode );
|
||||
else
|
||||
avlNode = rightLeftRotation( avlNode );
|
||||
}
|
||||
else
|
||||
; // Duplicate; do nothing
|
||||
avlNode.height = max( height( avlNode.left ), height( avlNode.right ) ) + 1;
|
||||
return avlNode;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param avlNode
|
||||
* @return
|
||||
*/
|
||||
private AVLNode leftRotation(AVLNode avlNode){
|
||||
AVLNode k1 = avlNode.left;
|
||||
avlNode.left = k1.right;
|
||||
k1.right = avlNode;
|
||||
avlNode.height = max( height( avlNode.left ), height( avlNode.right ) ) + 1;
|
||||
k1.height = max( height( k1.left ), avlNode.height ) + 1;
|
||||
return k1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param avlNode
|
||||
* @return
|
||||
*/
|
||||
private AVLNode rightRotation(AVLNode avlNode){
|
||||
AVLNode node = avlNode.right;
|
||||
avlNode.right = node.left;
|
||||
node.left = avlNode;
|
||||
avlNode.height = max( height( avlNode.left ), height( avlNode.right ) ) + 1;
|
||||
node.height = max( height( node.right ), avlNode.height ) + 1;
|
||||
return node;
|
||||
}
|
||||
/**
|
||||
* left-right rotation
|
||||
* @param avlNode
|
||||
* @return
|
||||
*/
|
||||
private AVLNode leftRightRotation(AVLNode avlNode){
|
||||
avlNode.left = rightRotation( avlNode.left );
|
||||
return leftRotation( avlNode );
|
||||
}
|
||||
|
||||
/**
|
||||
* right-left rotation
|
||||
* @param avlNode
|
||||
* @return
|
||||
*/
|
||||
private AVLNode rightLeftRotation(AVLNode avlNode)
|
||||
{
|
||||
avlNode.right = leftRotation( avlNode.right );
|
||||
return rightRotation( avlNode );
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int countNodes(){
|
||||
return countNodes(root);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param avlNode
|
||||
* @return
|
||||
*/
|
||||
private int countNodes(AVLNode avlNode){
|
||||
if (avlNode == null)
|
||||
return 0;
|
||||
else{
|
||||
int l = 1;
|
||||
l += countNodes(avlNode.left);
|
||||
l += countNodes(avlNode.right);
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
public boolean search(int data){
|
||||
return search(root, data);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param avlNode
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
private boolean search(AVLNode avlNode, int data){
|
||||
boolean found = false;
|
||||
while ((avlNode != null) && !found)
|
||||
{
|
||||
int rval = avlNode.data;
|
||||
if (data < rval)
|
||||
avlNode = avlNode.left;
|
||||
else if (data > rval)
|
||||
avlNode = avlNode.right;
|
||||
else
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
found = search(avlNode, data);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void inorder(){
|
||||
inorder(root);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param avlNode
|
||||
*/
|
||||
private void inorder(AVLNode avlNode){
|
||||
if (avlNode != null){
|
||||
inorder(avlNode.left);
|
||||
System.out.print(avlNode.data +" ");
|
||||
inorder(avlNode.right);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package javadevjournal.ds.avl;
|
||||
|
||||
import java.util.Scanner;
|
||||
|
||||
public class AVLTreeHelper{
|
||||
public static void main(String[] args){
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
AVLTree avlTree = new AVLTree();
|
||||
|
||||
char ch;
|
||||
do{
|
||||
System.out.println("\nAVLTree Operations\n");
|
||||
System.out.println("1. insert ");
|
||||
System.out.println("2. search");
|
||||
System.out.println("3. count nodes");
|
||||
int choice = scanner.nextInt();
|
||||
switch (choice)
|
||||
{
|
||||
case 1 :
|
||||
System.out.println("Enter integer element to insert");
|
||||
avlTree.insert( scanner.nextInt() );
|
||||
break;
|
||||
case 2 :
|
||||
System.out.println("Enter integer element to search");
|
||||
System.out.println("Search result : "+ avlTree.search( scanner.nextInt()));
|
||||
break;
|
||||
case 3 :
|
||||
System.out.println("Nodes = "+ avlTree.countNodes());
|
||||
break;
|
||||
default :
|
||||
System.out.println("Wrong Entry \n ");
|
||||
break;
|
||||
}
|
||||
|
||||
System.out.print("\nIn order : ");
|
||||
avlTree.inorder();
|
||||
|
||||
System.out.println("\nDo you want to continue (Type y or n) \n");
|
||||
ch = scanner.next().charAt(0);
|
||||
} while (ch == 'Y'|| ch == 'y');
|
||||
}
|
||||
}
|
||||
8
java-tutorials/.idea/.gitignore
generated
vendored
Normal file
8
java-tutorials/.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
5
java-tutorials/.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
java-tutorials/.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
||||
@@ -122,19 +122,31 @@
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.apache.directory.server</groupId>-->
|
||||
<!-- <artifactId>apacheds-core</artifactId>-->
|
||||
<!-- <version>1.5.7</version>-->
|
||||
<!-- <scope>runtime</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.apache.directory.server</groupId>-->
|
||||
<!-- <artifactId>apacheds-server-jndi</artifactId>-->
|
||||
<!-- <version>1.5.7</version>-->
|
||||
<!-- <scope>runtime</scope>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-core</artifactId>
|
||||
<version>1.5.7</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-server-jndi</artifactId>
|
||||
<version>1.5.7</version>
|
||||
<scope>runtime</scope>
|
||||
<groupId>com.unboundid</groupId>
|
||||
<artifactId>unboundid-ldapsdk</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- dependency for the MFA -->
|
||||
<dependency>
|
||||
<groupId>dev.samstevens.totp</groupId>
|
||||
<artifactId>totp</artifactId>
|
||||
<version>1.7.1</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
<build>
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
|
||||
<output url="file://$MODULE_DIR$/target/classes" />
|
||||
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-devtools:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.2.7.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-logging:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.2.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.2.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-to-slf4j:2.13.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-api:2.13.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.slf4j:jul-to-slf4j:1.7.30" level="project" />
|
||||
<orderEntry type="library" name="Maven: jakarta.annotation:jakarta.annotation-api:1.3.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.2.7.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.2.7.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.26" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-security:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.2.7.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.2.7.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-config:5.3.3.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.3.3.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-web:5.3.3.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.2.7.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-web:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-json:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.11.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.11.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.11.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-tomcat:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-core:9.0.36" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-websocket:9.0.36" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-web:5.2.7.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-webmvc:5.2.7.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-validation:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.glassfish:jakarta.el:3.0.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.hibernate.validator:hibernate-validator:6.1.5.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: jakarta.validation:jakarta.validation-api:2.0.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.4.1.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml:classmate:1.5.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-thymeleaf:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.thymeleaf:thymeleaf-spring5:3.0.11.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.thymeleaf:thymeleaf:3.0.11.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.attoparser:attoparser:2.0.5.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.unbescape:unbescape:1.1.6.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.thymeleaf.extras:thymeleaf-extras-java8time:3.0.4.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-jpa:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-aop:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.aspectj:aspectjweaver:1.9.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.zaxxer:HikariCP:3.4.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-jdbc:5.2.7.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: jakarta.transaction:jakarta.transaction-api:1.3.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: jakarta.persistence:jakarta.persistence-api:2.2.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.hibernate:hibernate-core:5.4.17.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.javassist:javassist:3.24.0-GA" level="project" />
|
||||
<orderEntry type="library" name="Maven: net.bytebuddy:byte-buddy:1.10.11" level="project" />
|
||||
<orderEntry type="library" name="Maven: antlr:antlr:2.7.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.jboss:jandex:2.1.3.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.dom4j:dom4j:2.1.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.hibernate.common:hibernate-commons-annotations:5.1.0.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.glassfish.jaxb:jaxb-runtime:2.3.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.glassfish.jaxb:txw2:2.3.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.sun.istack:istack-commons-runtime:3.0.11" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-jpa:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-commons:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-orm:5.2.7.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-tx:5.2.7.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-aspects:5.2.7.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-actuator:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-actuator-autoconfigure:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-actuator:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.micrometer:micrometer-core:1.5.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.hdrhistogram:HdrHistogram:2.1.12" level="project" />
|
||||
<orderEntry type="library" scope="RUNTIME" name="Maven: org.latencyutils:LatencyUtils:2.0.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: mysql:mysql-connector-java:8.0.18" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-mail:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-context-support:5.2.7.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.sun.mail:jakarta.mail:1.6.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.sun.activation:jakarta.activation:1.2.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.11" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.0.4.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.30" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.session:spring-session-data-redis:2.3.0.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-redis:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-keyvalue:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-oxm:5.2.7.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.session:spring-session-core:2.3.0.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-redis:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.lettuce:lettuce-core:5.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-common:4.1.50.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-handler:4.1.50.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-resolver:4.1.50.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-buffer:4.1.50.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-codec:4.1.50.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-transport:4.1.50.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.projectreactor:reactor-core:3.3.6.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-collections4:4.4" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-starter-test:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test-autoconfigure:2.3.1.RELEASE" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: com.jayway.jsonpath:json-path:2.4.0" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: net.minidev:json-smart:2.3" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: net.minidev:accessors-smart:1.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.ow2.asm:asm:5.0.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: jakarta.xml.bind:jakarta.xml.bind-api:2.3.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: jakarta.activation:jakarta.activation-api:1.2.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.assertj:assertj-core:3.16.1" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest:2.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter:5.6.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-api:5.6.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.apiguardian:apiguardian-api:1.1.0" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.opentest4j:opentest4j:1.2.0" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.junit.platform:junit-platform-commons:1.6.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-params:5.6.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-engine:5.6.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.junit.platform:junit-platform-engine:1.6.2" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-core:3.3.3" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: net.bytebuddy:byte-buddy-agent:1.10.11" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.objenesis:objenesis:2.6" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-junit-jupiter:3.3.3" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.skyscreamer:jsonassert:1.5.0" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: com.vaadin.external.google:android-json:0.0.20131108.vaadin1" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.springframework:spring-test:5.2.7.RELEASE" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.xmlunit:xmlunit-core:2.7.0" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -1,5 +1,14 @@
|
||||
package com.javadevjournal.config;
|
||||
|
||||
import dev.samstevens.totp.code.CodeVerifier;
|
||||
import dev.samstevens.totp.code.DefaultCodeGenerator;
|
||||
import dev.samstevens.totp.code.DefaultCodeVerifier;
|
||||
import dev.samstevens.totp.qr.QrGenerator;
|
||||
import dev.samstevens.totp.qr.ZxingPngQrGenerator;
|
||||
import dev.samstevens.totp.secret.DefaultSecretGenerator;
|
||||
import dev.samstevens.totp.secret.SecretGenerator;
|
||||
import dev.samstevens.totp.time.SystemTimeProvider;
|
||||
import dev.samstevens.totp.time.TimeProvider;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -68,4 +77,20 @@ public class AppConfig implements WebMvcConfigurer {
|
||||
}
|
||||
|
||||
// setting up thymeleaf for Spring Email TemplateEngine
|
||||
|
||||
@Bean
|
||||
public SecretGenerator secretGenerator(){
|
||||
return new DefaultSecretGenerator(64);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public QrGenerator qrGenerator(){
|
||||
return new ZxingPngQrGenerator();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CodeVerifier codeVerifier(){
|
||||
return new DefaultCodeVerifier(new DefaultCodeGenerator(), new SystemTimeProvider());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,36 +2,28 @@ package com.javadevjournal.core.security;
|
||||
|
||||
import com.javadevjournal.core.security.authentication.CustomAuthenticationProvider;
|
||||
import com.javadevjournal.core.security.filter.CustomAuthenticationFilter;
|
||||
import com.javadevjournal.core.security.filter.CustomHeaderAuthFilter;
|
||||
import com.javadevjournal.core.security.handlers.CustomAccessDeniedHandler;
|
||||
import com.javadevjournal.core.security.handlers.CustomSuccessHandler;
|
||||
import com.javadevjournal.core.security.handlers.LoginAuthenticationFailureHandler;
|
||||
import com.javadevjournal.core.security.web.authentication.CustomWebAuthenticationDetails;
|
||||
import com.javadevjournal.core.security.web.authentication.CustomWebAuthenticationDetailsSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
|
||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||
import org.springframework.security.authentication.AuthenticationEventPublisher;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
|
||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.configurers.ldap.LdapAuthenticationProviderConfigurer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
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.session.SessionRegistry;
|
||||
import org.springframework.security.core.session.SessionRegistryImpl;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.ldap.authentication.BindAuthenticator;
|
||||
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
|
||||
import org.springframework.security.ldap.authentication.LdapAuthenticator;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetails;
|
||||
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
|
||||
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
|
||||
@@ -47,14 +39,17 @@ public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@Resource
|
||||
UserDetailsService userDetailsService;
|
||||
|
||||
@Autowired
|
||||
@Resource
|
||||
PasswordEncoder passwordEncoder;
|
||||
|
||||
@Autowired
|
||||
@Resource
|
||||
private DataSource dataSource;
|
||||
|
||||
@Resource
|
||||
CustomAuthenticationProvider customAuthenticationProvider;
|
||||
private CustomAuthenticationProvider customAuthenticationProvider;
|
||||
|
||||
@Resource
|
||||
private CustomWebAuthenticationDetailsSource authenticationDetailsSource;
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
@@ -68,7 +63,6 @@ public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
//Setting HTTPS for my account
|
||||
.requiresChannel().anyRequest().requiresSecure()
|
||||
.and()
|
||||
|
||||
// Remember me configurations
|
||||
.rememberMe().tokenRepository(persistentTokenRepository())
|
||||
.rememberMeCookieDomain("domain")
|
||||
@@ -85,6 +79,7 @@ public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
.failureUrl("/login?error=true")
|
||||
.successHandler(successHandler())
|
||||
.failureHandler(failureHandler())
|
||||
.authenticationDetailsSource(authenticationDetailsSource) //injecting custom authenitcation source
|
||||
//logout configurations
|
||||
.and()
|
||||
.logout().deleteCookies("dummyCookie")
|
||||
@@ -97,15 +92,16 @@ public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
|
||||
http.authorizeRequests().antMatchers("/admim/**").hasAuthority("ADMIN");
|
||||
http.addFilterAfter(customHeaderAuthFilter(), UsernamePasswordAuthenticationFilter.class);
|
||||
//http.addFilterAfter(customHeaderAuthFilter(), UsernamePasswordAuthenticationFilter.class);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
/* @Bean
|
||||
public CustomHeaderAuthFilter customHeaderAuthFilter(){
|
||||
return new CustomHeaderAuthFilter();
|
||||
}
|
||||
} */
|
||||
|
||||
|
||||
private AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> authenticationDetailsSource() {
|
||||
@@ -138,14 +134,14 @@ public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
return new CustomAccessDeniedHandler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
/* @Bean
|
||||
public CustomAuthenticationFilter authFilter() throws Exception {
|
||||
CustomAuthenticationFilter filter = new CustomAuthenticationFilter();
|
||||
filter.setAuthenticationManager(authenticationManagerBean());
|
||||
filter.setAuthenticationFailureHandler(failureHandler());
|
||||
filter.setAuthenticationSuccessHandler(successHandler());
|
||||
return filter;
|
||||
}
|
||||
} */
|
||||
|
||||
@Bean
|
||||
public LoginAuthenticationFailureHandler failureHandler(){
|
||||
@@ -188,14 +184,13 @@ public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
* DAO authentication provider. This authentication provider will authenticate the user with the help of
|
||||
* @UserdetailsService. This is based on the validating the user with the username and password.
|
||||
* @return
|
||||
*/
|
||||
|
||||
@Bean
|
||||
public DaoAuthenticationProvider authProvider() {
|
||||
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
|
||||
authenticationProvider.setPasswordEncoder(passwordEncoder);
|
||||
public CustomAuthenticationProvider authProvider() {
|
||||
CustomAuthenticationProvider authenticationProvider = new CustomAuthenticationProvider();
|
||||
authenticationProvider.setUserDetailsService(userDetailsService);
|
||||
return authenticationProvider;
|
||||
}
|
||||
} */
|
||||
|
||||
/**
|
||||
* Authentication manager which will be invoked by Spring security filter chain. This authentication
|
||||
@@ -206,11 +201,11 @@ public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
*/
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth){
|
||||
//auth.authenticationProvider(authProvider());
|
||||
auth.authenticationProvider(customAuthenticationProvider)
|
||||
.authenticationProvider(authProvider());
|
||||
auth.authenticationProvider(customAuthenticationProvider);
|
||||
//auth.authenticationProvider(customAuthenticationProvider).authenticationProvider(authProvider());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Using this to persist the remember-me token in the database for more secure approach.
|
||||
* We are not usin gthe memory based remember-me cookie which is not very secure but saving the token in the
|
||||
@@ -226,6 +221,7 @@ public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
//Spring security LDAP configurations
|
||||
|
||||
/*
|
||||
@Bean
|
||||
BindAuthenticator authenticator(BaseLdapPathContextSource contextSource) {
|
||||
BindAuthenticator authenticator = new BindAuthenticator(contextSource);
|
||||
@@ -237,5 +233,5 @@ public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@Bean
|
||||
LdapAuthenticationProvider authenticationProvider(LdapAuthenticator authenticator) {
|
||||
return new LdapAuthenticationProvider(authenticator);
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
@@ -1,50 +1,51 @@
|
||||
package com.javadevjournal.core.security.authentication;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
|
||||
import com.javadevjournal.core.security.core.userdetail.CustomUser;
|
||||
import com.javadevjournal.core.security.mfa.MFATokenManager;
|
||||
import com.javadevjournal.core.security.web.authentication.CustomWebAuthenticationDetails;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
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.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@Component
|
||||
public class CustomAuthenticationProvider implements AuthenticationProvider {
|
||||
public class CustomAuthenticationProvider extends DaoAuthenticationProvider {
|
||||
|
||||
@Resource
|
||||
UserDetailsService userDetailsService;
|
||||
private MFATokenManager mfaTokenManager;
|
||||
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
final String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED" : authentication.getName();
|
||||
@Resource
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
if (StringUtils.isEmpty(username)) {
|
||||
throw new BadCredentialsException("invalid login details");
|
||||
@Autowired
|
||||
public CustomAuthenticationProvider(UserDetailsService userDetailsService) {
|
||||
super.setUserDetailsService(userDetailsService);
|
||||
}
|
||||
|
||||
protected void additionalAuthenticationChecks(UserDetails userDetails,
|
||||
UsernamePasswordAuthenticationToken authentication)
|
||||
throws AuthenticationException {
|
||||
|
||||
super.additionalAuthenticationChecks(userDetails, authentication);
|
||||
|
||||
//token check
|
||||
CustomWebAuthenticationDetails authenticationDetails = (CustomWebAuthenticationDetails) authentication.getDetails();
|
||||
CustomUser user = (CustomUser) userDetails;
|
||||
String mfaToken = authenticationDetails.getToken();
|
||||
if(!mfaTokenManager.verifyTotp(mfaToken,user.getSecret())){
|
||||
throw new BadCredentialsException(messages.getMessage(
|
||||
"AbstractUserDetailsAuthenticationProvider.badCredentials",
|
||||
"Bad credentials"));
|
||||
}
|
||||
// get user details using Spring security user details service
|
||||
UserDetails user = null;
|
||||
try {
|
||||
user = userDetailsService.loadUserByUsername(username);
|
||||
|
||||
} catch (UsernameNotFoundException exception) {
|
||||
throw new BadCredentialsException("invalid login details");
|
||||
}
|
||||
return createSuccessfulAuthentication(authentication, user);
|
||||
}
|
||||
|
||||
private Authentication createSuccessfulAuthentication(final Authentication authentication, final UserDetails user) {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getUsername(), authentication.getCredentials(), user.getAuthorities());
|
||||
token.setDetails(authentication.getDetails());
|
||||
return token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> authentication) {
|
||||
return authentication.equals(UsernamePasswordAuthenticationToken.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,21 +13,22 @@ import java.util.function.Function;
|
||||
public class CustomUser implements UserDetails {
|
||||
|
||||
private String password;
|
||||
private final String username;
|
||||
private final Set<GrantedAuthority> authorities;
|
||||
private final boolean accountNonExpired;
|
||||
private final boolean accountNonLocked;
|
||||
private final boolean credentialsNonExpired;
|
||||
private final boolean enabled;
|
||||
private String username;
|
||||
private Collection<GrantedAuthority> authorities;
|
||||
private boolean accountNonExpired;
|
||||
private boolean accountNonLocked;
|
||||
private boolean credentialsNonExpired;
|
||||
private boolean enabled;
|
||||
private String secret;
|
||||
|
||||
public CustomUser(String username, String password,
|
||||
Collection<? extends GrantedAuthority> authorities) {
|
||||
this(username, password, true, true, true, true, authorities);
|
||||
Collection<? extends GrantedAuthority> authorities, String secret) {
|
||||
this(username, password, true, true, true, true, authorities, secret);
|
||||
}
|
||||
|
||||
public CustomUser(String username, String password, boolean enabled,
|
||||
boolean accountNonExpired, boolean credentialsNonExpired,
|
||||
boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
|
||||
boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities, final String secret) {
|
||||
|
||||
if (((username == null) || "".equals(username)) || (password == null)) {
|
||||
throw new IllegalArgumentException(
|
||||
@@ -41,6 +42,7 @@ public class CustomUser implements UserDetails {
|
||||
this.credentialsNonExpired = credentialsNonExpired;
|
||||
this.accountNonLocked = accountNonLocked;
|
||||
this.authorities = null;
|
||||
this.secret= secret;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,6 +78,10 @@ public class CustomUser implements UserDetails {
|
||||
password = null;
|
||||
}
|
||||
|
||||
public String getSecret() {
|
||||
return secret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object rhs) {
|
||||
if (rhs instanceof CustomUser) {
|
||||
@@ -89,209 +95,68 @@ public class CustomUser implements UserDetails {
|
||||
return username.hashCode();
|
||||
}
|
||||
|
||||
public static CustomUser.UserBuilder withUsername(String username) {
|
||||
return builder().username(username);
|
||||
}
|
||||
|
||||
public static CustomUser.UserBuilder builder() {
|
||||
return new CustomUser.UserBuilder();
|
||||
}
|
||||
|
||||
public static CustomUser.UserBuilder withUserDetails(UserDetails userDetails) {
|
||||
return withUsername(userDetails.getUsername())
|
||||
.password(userDetails.getPassword())
|
||||
.accountExpired(!userDetails.isAccountNonExpired())
|
||||
.accountLocked(!userDetails.isAccountNonLocked())
|
||||
.authorities(userDetails.getAuthorities())
|
||||
.credentialsExpired(!userDetails.isCredentialsNonExpired())
|
||||
.disabled(!userDetails.isEnabled());
|
||||
}
|
||||
|
||||
public static class UserBuilder {
|
||||
private String username;
|
||||
public static final class CustomUserBuilder {
|
||||
private String password;
|
||||
private List<GrantedAuthority> authorities;
|
||||
private boolean accountExpired;
|
||||
private boolean accountLocked;
|
||||
private boolean credentialsExpired;
|
||||
private boolean disabled;
|
||||
private Function<String, String> passwordEncoder = password -> password;
|
||||
private String username;
|
||||
private Collection<GrantedAuthority> authorities;
|
||||
private boolean accountNonExpired;
|
||||
private boolean accountNonLocked;
|
||||
private boolean credentialsNonExpired;
|
||||
private boolean enabled;
|
||||
private String secret;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*/
|
||||
private UserBuilder() {
|
||||
private CustomUserBuilder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the username. This attribute is required.
|
||||
*
|
||||
* @param username the username. Cannot be null.
|
||||
* @return the {@link User.UserBuilder} for method chaining (i.e. to populate
|
||||
* additional attributes for this user)
|
||||
*/
|
||||
public CustomUser.UserBuilder username(String username) {
|
||||
Assert.notNull(username, "username cannot be null");
|
||||
this.username = username;
|
||||
return this;
|
||||
public static CustomUserBuilder aCustomUser() {
|
||||
return new CustomUserBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the password. This attribute is required.
|
||||
*
|
||||
* @param password the password. Cannot be null.
|
||||
* @return the {@link User.UserBuilder} for method chaining (i.e. to populate
|
||||
* additional attributes for this user)
|
||||
*/
|
||||
public CustomUser.UserBuilder password(String password) {
|
||||
Assert.notNull(password, "password cannot be null");
|
||||
public CustomUserBuilder withPassword(String password) {
|
||||
this.password = password;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the current password (if non-null) and any future passwords supplied
|
||||
* to {@link #password(String)}.
|
||||
*
|
||||
* @param encoder the encoder to use
|
||||
* @return the {@link User.UserBuilder} for method chaining (i.e. to populate
|
||||
* additional attributes for this user)
|
||||
*/
|
||||
public CustomUser.UserBuilder passwordEncoder(Function<String, String> encoder) {
|
||||
Assert.notNull(encoder, "encoder cannot be null");
|
||||
this.passwordEncoder = encoder;
|
||||
public CustomUserBuilder withUsername(String username) {
|
||||
this.username = username;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the roles. This method is a shortcut for calling
|
||||
* {@link #authorities(String...)}, but automatically prefixes each entry with
|
||||
* "ROLE_". This means the following:
|
||||
*
|
||||
* <code>
|
||||
* builder.roles("USER","ADMIN");
|
||||
* </code>
|
||||
*
|
||||
* is equivalent to
|
||||
*
|
||||
* <code>
|
||||
* builder.authorities("ROLE_USER","ROLE_ADMIN");
|
||||
* </code>
|
||||
*
|
||||
* <p>
|
||||
* This attribute is required, but can also be populated with
|
||||
* {@link #authorities(String...)}.
|
||||
* </p>
|
||||
*
|
||||
* @param roles the roles for this user (i.e. USER, ADMIN, etc). Cannot be null,
|
||||
* contain null values or start with "ROLE_"
|
||||
* @return the {@link User.UserBuilder} for method chaining (i.e. to populate
|
||||
* additional attributes for this user)
|
||||
*/
|
||||
public CustomUser.UserBuilder roles(String... roles) {
|
||||
List<GrantedAuthority> authorities = new ArrayList<>(
|
||||
roles.length);
|
||||
for (String role : roles) {
|
||||
Assert.isTrue(!role.startsWith("ROLE_"), () -> role
|
||||
+ " cannot start with ROLE_ (it is automatically added)");
|
||||
authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
|
||||
}
|
||||
return authorities(authorities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the authorities. This attribute is required.
|
||||
*
|
||||
* @param authorities the authorities for this user. Cannot be null, or contain
|
||||
* null values
|
||||
* @return the {@link User.UserBuilder} for method chaining (i.e. to populate
|
||||
* additional attributes for this user)
|
||||
* @see #roles(String...)
|
||||
*/
|
||||
public CustomUser.UserBuilder authorities(GrantedAuthority... authorities) {
|
||||
return authorities(Arrays.asList(authorities));
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the authorities. This attribute is required.
|
||||
*
|
||||
* @param authorities the authorities for this user. Cannot be null, or contain
|
||||
* null values
|
||||
* @return the {@link User.UserBuilder} for method chaining (i.e. to populate
|
||||
* additional attributes for this user)
|
||||
* @see #roles(String...)
|
||||
*/
|
||||
public CustomUser.UserBuilder authorities(Collection<? extends GrantedAuthority> authorities) {
|
||||
this.authorities = new ArrayList<>(authorities);
|
||||
public CustomUserBuilder withAuthorities(Collection<GrantedAuthority> authorities) {
|
||||
this.authorities = authorities;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the authorities. This attribute is required.
|
||||
*
|
||||
* @param authorities the authorities for this user (i.e. ROLE_USER, ROLE_ADMIN,
|
||||
* etc). Cannot be null, or contain null values
|
||||
* @return the {@link User.UserBuilder} for method chaining (i.e. to populate
|
||||
* additional attributes for this user)
|
||||
* @see #roles(String...)
|
||||
*/
|
||||
public CustomUser.UserBuilder authorities(String... authorities) {
|
||||
return authorities(AuthorityUtils.createAuthorityList(authorities));
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines if the account is expired or not. Default is false.
|
||||
*
|
||||
* @param accountExpired true if the account is expired, false otherwise
|
||||
* @return the {@link User.UserBuilder} for method chaining (i.e. to populate
|
||||
* additional attributes for this user)
|
||||
*/
|
||||
public CustomUser.UserBuilder accountExpired(boolean accountExpired) {
|
||||
this.accountExpired = accountExpired;
|
||||
public CustomUserBuilder withAccountNonExpired(boolean accountNonExpired) {
|
||||
this.accountNonExpired = accountNonExpired;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines if the account is locked or not. Default is false.
|
||||
*
|
||||
* @param accountLocked true if the account is locked, false otherwise
|
||||
* @return the {@link User.UserBuilder} for method chaining (i.e. to populate
|
||||
* additional attributes for this user)
|
||||
*/
|
||||
public CustomUser.UserBuilder accountLocked(boolean accountLocked) {
|
||||
this.accountLocked = accountLocked;
|
||||
public CustomUserBuilder withAccountNonLocked(boolean accountNonLocked) {
|
||||
this.accountNonLocked = accountNonLocked;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines if the credentials are expired or not. Default is false.
|
||||
*
|
||||
* @param credentialsExpired true if the credentials are expired, false otherwise
|
||||
* @return the {@link User.UserBuilder} for method chaining (i.e. to populate
|
||||
* additional attributes for this user)
|
||||
*/
|
||||
public CustomUser.UserBuilder credentialsExpired(boolean credentialsExpired) {
|
||||
this.credentialsExpired = credentialsExpired;
|
||||
public CustomUserBuilder withCredentialsNonExpired(boolean credentialsNonExpired) {
|
||||
this.credentialsNonExpired = credentialsNonExpired;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines if the account is disabled or not. Default is false.
|
||||
*
|
||||
* @param disabled true if the account is disabled, false otherwise
|
||||
* @return the {@link User.UserBuilder} for method chaining (i.e. to populate
|
||||
* additional attributes for this user)
|
||||
*/
|
||||
public CustomUser.UserBuilder disabled(boolean disabled) {
|
||||
this.disabled = disabled;
|
||||
public CustomUserBuilder withEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public UserDetails build() {
|
||||
String encodedPassword = this.passwordEncoder.apply(password);
|
||||
return new CustomUser(username, encodedPassword, !disabled, !accountExpired,
|
||||
!credentialsExpired, !accountLocked, authorities);
|
||||
public CustomUserBuilder withSecret(String secret) {
|
||||
this.secret = secret;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CustomUser build() {
|
||||
CustomUser customUser = new CustomUser(username, password, !enabled, !accountNonExpired, !credentialsNonExpired, !accountNonLocked, authorities, secret);
|
||||
customUser.authorities = this.authorities;
|
||||
return customUser;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,26 +28,21 @@ public class CustomUserDetailService implements UserDetailsService{
|
||||
UserRepository userRepository;
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
|
||||
//Let's split the email to get both values
|
||||
String[] usernameAndCustomToken = StringUtils.split(email, String.valueOf(Character.LINE_SEPARATOR));
|
||||
public CustomUser loadUserByUsername(String email) throws UsernameNotFoundException {
|
||||
|
||||
//if the String arrays is empty or size is not equal to 2, let's throw exception
|
||||
if(Objects.isNull(usernameAndCustomToken) || usernameAndCustomToken.length !=2){
|
||||
throw new UsernameNotFoundException("User not found");
|
||||
}
|
||||
final String userName = usernameAndCustomToken[0];
|
||||
final String customToken = usernameAndCustomToken[1]; // use it based on your requirement
|
||||
final UserEntity customer = userRepository.findByEmail(userName);
|
||||
final UserEntity customer = userRepository.findByEmail(email);
|
||||
if (customer == null) {
|
||||
throw new UsernameNotFoundException(email);
|
||||
}
|
||||
boolean enabled = !customer.isAccountVerified(); // we can use this in case we want to activate account after customer verified the account
|
||||
UserDetails user = User.withUsername(customer.getEmail())
|
||||
.password(customer.getPassword())
|
||||
.disabled(customer.isLoginDisabled())
|
||||
.authorities(getAuthorities(customer)).build()
|
||||
;
|
||||
CustomUser user = CustomUser.CustomUserBuilder.aCustomUser().
|
||||
withUsername(customer.getEmail())
|
||||
.withPassword(customer.getPassword())
|
||||
.withEnabled(customer.isLoginDisabled())
|
||||
.withAuthorities(getAuthorities(customer))
|
||||
.withSecret(customer.getSecret())
|
||||
.withAccountNonLocked(false)
|
||||
.build();
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
@@ -18,8 +18,9 @@ public class CustomHeaderAuthFilter extends GenericFilterBean {
|
||||
|
||||
var request = (HttpServletRequest) servletRequest;
|
||||
var response = (HttpServletResponse)servletResponse;
|
||||
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
//if header is missing , send un-athorized error back
|
||||
/*
|
||||
String authHeader = request.getHeader("X-HEADER");
|
||||
if(StringUtils.isEmpty(authHeader)){
|
||||
response.setStatus(
|
||||
@@ -27,6 +28,6 @@ public class CustomHeaderAuthFilter extends GenericFilterBean {
|
||||
}
|
||||
else{
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
}
|
||||
} */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.javadevjournal.core.security.mfa;
|
||||
|
||||
import dev.samstevens.totp.code.CodeVerifier;
|
||||
import dev.samstevens.totp.code.HashingAlgorithm;
|
||||
import dev.samstevens.totp.exceptions.QrGenerationException;
|
||||
import dev.samstevens.totp.qr.QrData;
|
||||
import dev.samstevens.totp.qr.QrGenerator;
|
||||
import dev.samstevens.totp.secret.SecretGenerator;
|
||||
import dev.samstevens.totp.util.Utils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@Service("mfaTokenManager")
|
||||
public class DefaultMFATokenManager implements MFATokenManager{
|
||||
|
||||
@Resource
|
||||
private SecretGenerator secretGenerator;
|
||||
|
||||
@Resource
|
||||
private QrGenerator qrGenerator;
|
||||
|
||||
@Resource
|
||||
private CodeVerifier codeVerifier;
|
||||
|
||||
@Override
|
||||
public String generateSecretKey() {
|
||||
return secretGenerator.generate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQRCode(String secret) throws QrGenerationException {
|
||||
QrData data = new QrData.Builder().label("MFA")
|
||||
.secret(secret)
|
||||
.issuer("Java Development Journal")
|
||||
.algorithm(HashingAlgorithm.SHA256)
|
||||
.digits(6)
|
||||
.period(30)
|
||||
.build();
|
||||
return Utils.getDataUriForImage(
|
||||
qrGenerator.generate(data),
|
||||
qrGenerator.getImageMimeType()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verifyTotp(String code, String secret) {
|
||||
return codeVerifier.isValidCode(secret, code);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.javadevjournal.core.security.mfa;
|
||||
|
||||
import dev.samstevens.totp.exceptions.QrGenerationException;
|
||||
|
||||
public interface MFATokenManager {
|
||||
|
||||
String generateSecretKey();
|
||||
String getQRCode(final String secret) throws QrGenerationException;
|
||||
boolean verifyTotp(final String code, final String secret);
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import java.util.Objects;
|
||||
|
||||
public class CustomWebAuthenticationDetails extends WebAuthenticationDetails {
|
||||
|
||||
private final String token;
|
||||
private String token;
|
||||
/**
|
||||
* Records the remote address and will also set the session Id if a session already
|
||||
* exists (it won't create one).
|
||||
@@ -40,4 +40,12 @@ public class CustomWebAuthenticationDetails extends WebAuthenticationDetails {
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), token);
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.javadevjournal.core.security.web.authentication;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetails;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@Component
|
||||
public class CustomWebAuthenticationDetailsSource implements AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> {
|
||||
|
||||
@Override
|
||||
public CustomWebAuthenticationDetails buildDetails(HttpServletRequest context) {
|
||||
return new CustomWebAuthenticationDetails(context);
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,9 @@ public class UserEntity {
|
||||
private int failedLoginAttempts;
|
||||
private boolean loginDisabled;
|
||||
|
||||
private boolean mfaEnabled;
|
||||
private String secret;
|
||||
|
||||
@OneToMany(mappedBy = "user")
|
||||
private Set<SecureToken> tokens;
|
||||
|
||||
@@ -128,6 +131,22 @@ public class UserEntity {
|
||||
this.loginDisabled = loginDisabled;
|
||||
}
|
||||
|
||||
public boolean isMfaEnabled() {
|
||||
return mfaEnabled;
|
||||
}
|
||||
|
||||
public void setMfaEnabled(boolean mfaEnabled) {
|
||||
this.mfaEnabled = mfaEnabled;
|
||||
}
|
||||
|
||||
public String getSecret() {
|
||||
return secret;
|
||||
}
|
||||
|
||||
public void setSecret(String secret) {
|
||||
this.secret = secret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
||||
@@ -6,13 +6,16 @@ import com.javadevjournal.core.exception.InvalidTokenException;
|
||||
import com.javadevjournal.core.exception.UnkownIdentifierException;
|
||||
import com.javadevjournal.core.exception.UserAlreadyExistException;
|
||||
import com.javadevjournal.core.security.jpa.SecureToken;
|
||||
import com.javadevjournal.core.security.mfa.MFATokenManager;
|
||||
import com.javadevjournal.core.security.token.SecureTokenService;
|
||||
import com.javadevjournal.core.security.token.repository.SecureTokenRepository;
|
||||
import com.javadevjournal.core.user.jpa.data.Group;
|
||||
import com.javadevjournal.core.user.jpa.data.UserEntity;
|
||||
import com.javadevjournal.core.user.jpa.repository.UserGroupRepository;
|
||||
import com.javadevjournal.core.user.jpa.repository.UserRepository;
|
||||
import com.javadevjournal.web.data.user.MfaTokenData;
|
||||
import com.javadevjournal.web.data.user.UserData;
|
||||
import dev.samstevens.totp.exceptions.QrGenerationException;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
@@ -21,33 +24,37 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.mail.MessagingException;
|
||||
import java.util.Objects;
|
||||
|
||||
@Service("userService")
|
||||
public class DefaultUserService implements UserService{
|
||||
|
||||
@Autowired
|
||||
@Resource
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
@Resource
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Autowired
|
||||
@Resource
|
||||
private EmailService emailService;
|
||||
|
||||
@Autowired
|
||||
@Resource
|
||||
private SecureTokenService secureTokenService;
|
||||
|
||||
@Autowired
|
||||
@Resource
|
||||
SecureTokenRepository secureTokenRepository;
|
||||
|
||||
@Autowired
|
||||
@Resource
|
||||
UserGroupRepository groupRepository;
|
||||
|
||||
@Value("${site.base.url.https}")
|
||||
private String baseURL;
|
||||
|
||||
@Resource
|
||||
private MFATokenManager mfaTokenManager;
|
||||
|
||||
@Override
|
||||
public void register(UserData user) throws UserAlreadyExistException {
|
||||
if(checkIfUserExist(user.getEmail())){
|
||||
@@ -57,6 +64,7 @@ public class DefaultUserService implements UserService{
|
||||
BeanUtils.copyProperties(user, userEntity);
|
||||
encodePassword(user, userEntity);
|
||||
updateCustomerGroup(userEntity);
|
||||
userEntity.setSecret(mfaTokenManager.generateSecretKey());
|
||||
userRepository.save(userEntity);
|
||||
sendRegistrationConfirmationEmail(userEntity);
|
||||
|
||||
@@ -67,6 +75,7 @@ public class DefaultUserService implements UserService{
|
||||
userEntity.addUserGroups(group);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean checkIfUserExist(String email) {
|
||||
return userRepository.findByEmail(email)!=null ? true : false;
|
||||
@@ -83,7 +92,7 @@ public class DefaultUserService implements UserService{
|
||||
emailContext.buildVerificationUrl(baseURL, secureToken.getToken());
|
||||
try {
|
||||
emailService.sendMail(emailContext);
|
||||
} catch (MessagingException e) {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -117,6 +126,16 @@ public class DefaultUserService implements UserService{
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MfaTokenData mfaSetup(String email) throws UnkownIdentifierException, QrGenerationException {
|
||||
UserEntity user= userRepository.findByEmail(email);
|
||||
if(user == null ){
|
||||
// we will ignore in case account is not verified or account does not exists
|
||||
throw new UnkownIdentifierException("unable to find account or account is not active");
|
||||
}
|
||||
return new MfaTokenData( mfaTokenManager.getQRCode( user.getSecret()), user.getSecret());
|
||||
}
|
||||
|
||||
private void encodePassword(UserData source, UserEntity target){
|
||||
target.setPassword(passwordEncoder.encode(source.getPassword()));
|
||||
}
|
||||
|
||||
@@ -4,7 +4,9 @@ import com.javadevjournal.core.exception.InvalidTokenException;
|
||||
import com.javadevjournal.core.exception.UnkownIdentifierException;
|
||||
import com.javadevjournal.core.exception.UserAlreadyExistException;
|
||||
import com.javadevjournal.core.user.jpa.data.UserEntity;
|
||||
import com.javadevjournal.web.data.user.MfaTokenData;
|
||||
import com.javadevjournal.web.data.user.UserData;
|
||||
import dev.samstevens.totp.exceptions.QrGenerationException;
|
||||
|
||||
public interface UserService {
|
||||
|
||||
@@ -13,4 +15,5 @@ public interface UserService {
|
||||
void sendRegistrationConfirmationEmail(final UserEntity user);
|
||||
boolean verifyUser(final String token) throws InvalidTokenException;
|
||||
UserEntity getUserById(final String id) throws UnkownIdentifierException;
|
||||
MfaTokenData mfaSetup(final String email) throws UnkownIdentifierException, QrGenerationException;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package com.javadevjournal.web.controller.user;
|
||||
|
||||
import com.javadevjournal.core.exception.InvalidTokenException;
|
||||
import com.javadevjournal.core.exception.UnkownIdentifierException;
|
||||
import com.javadevjournal.core.exception.UserAlreadyExistException;
|
||||
import com.javadevjournal.core.user.service.UserService;
|
||||
import com.javadevjournal.web.data.user.MfaTokenData;
|
||||
import com.javadevjournal.web.data.user.UserData;
|
||||
import dev.samstevens.totp.exceptions.QrGenerationException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.MessageSource;
|
||||
@@ -17,6 +20,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
|
||||
import static com.javadevjournal.ApplicationConstant.REDIRECT;
|
||||
@@ -27,10 +31,10 @@ public class RegistrationController {
|
||||
|
||||
private static final String REDIRECT_LOGIN= "redirect:/login";
|
||||
|
||||
@Autowired
|
||||
@Resource
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
@Resource
|
||||
private MessageSource messageSource;
|
||||
|
||||
@GetMapping
|
||||
@@ -47,7 +51,11 @@ public class RegistrationController {
|
||||
}
|
||||
try {
|
||||
userService.register(userData);
|
||||
}catch (UserAlreadyExistException e){
|
||||
MfaTokenData mfaData = userService.mfaSetup(userData.getEmail());
|
||||
model.addAttribute("qrCode", mfaData.getQrCode());
|
||||
model.addAttribute("qrCodeKey", mfaData.getMfaCode());
|
||||
model.addAttribute("qrCodeSetup", true);
|
||||
}catch (UserAlreadyExistException | QrGenerationException | UnkownIdentifierException e){
|
||||
bindingResult.rejectValue("email", "userData.email","An account already exists for this email.");
|
||||
model.addAttribute("registrationForm", userData);
|
||||
return "account/register";
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.javadevjournal.web.data.user;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class MfaTokenData implements Serializable {
|
||||
|
||||
private String qrCode;
|
||||
private String mfaCode;
|
||||
|
||||
public MfaTokenData() {
|
||||
}
|
||||
|
||||
public String getQrCode() {
|
||||
return qrCode;
|
||||
}
|
||||
|
||||
public void setQrCode(String qrCode) {
|
||||
this.qrCode = qrCode;
|
||||
}
|
||||
|
||||
public String getMfaCode() {
|
||||
return mfaCode;
|
||||
}
|
||||
|
||||
public void setMfaCode(String mfaCode) {
|
||||
this.mfaCode = mfaCode;
|
||||
}
|
||||
|
||||
public MfaTokenData(String qrCode, String mfaCode) {
|
||||
this.qrCode = qrCode;
|
||||
this.mfaCode = mfaCode;
|
||||
}
|
||||
}
|
||||
@@ -63,3 +63,9 @@ jdj.security.failedlogin.count =2
|
||||
jdj.brute.force.cache.max=1000
|
||||
|
||||
|
||||
###### Spring LDAP configuration. This is using Apache DS server but you can use it for any other LDAP server
|
||||
#spring.ldap.embedded.ldif=classpath:users.ldif
|
||||
#spring.ldap.embedded.base-dn=dc=springframework,dc=org
|
||||
#spring.ldap.embedded.port=53389
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ login.error= Username or password is incorrect. Please make sure to provide vali
|
||||
user.registration.verification.missing.token= Token is empty. Please make sure to copy the entire URL
|
||||
user.registration.verification.invalid.token= It seems that token is expired or has been modified.Please provide a valid token.
|
||||
user.registration.verification.success= Thanks for the account verification. You can now login to your account.
|
||||
user.registration.verification.email.msg= Thanks for your registration. We have sent a verification email. Please verify your account.
|
||||
user.registration.verification.email.msg= Thanks for your registration. We have sent a verification email. Please verify your account.Please scan the QR code for generating MFA token for login.
|
||||
user.forgotpwd.msg= If the email address entered matches your account, you will receive an email with a link to reset your password.
|
||||
user.password.updated.msg= Your password is updated. Please login
|
||||
user.account.locked = Your account has been locked due to multiple failed login attempts.
|
||||
@@ -18,10 +18,16 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
|
||||
<div class="card-body register-card-body">
|
||||
<div class="alert alert-success" role="alert" th:if="${registrationMsg != null}">
|
||||
<p th:text="${registrationMsg}"></p>
|
||||
</div>
|
||||
<div th:if="${registrationMsg != null}">
|
||||
<img class="col-md-12" th:src="${qrCode}" />
|
||||
<p th:text="${qrCodeKey}"></p>
|
||||
</div>
|
||||
<div th:if="${registrationMsg == null}">
|
||||
<p class="login-box-msg">Register a new account</p>
|
||||
<form action="#" th:action="@{/register}" th:object="${userData}" method="post">
|
||||
<div class="alert alert-danger" th:if="${#fields.hasErrors('*')}">
|
||||
@@ -90,7 +96,7 @@
|
||||
<!-- /.col -->
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
<a href="login" class="text-center">I already have an Account</a>
|
||||
</div>
|
||||
<!-- /.form-box -->
|
||||
|
||||
Reference in New Issue
Block a user