SpringBoot – Little Big Extra http://www.littlebigextra.com A technology blog covering topics on Java, Scala, Docker, AWS, BigData, DevOps and much more to come. Do it yourself instructions for complex to simple problems for a novice to an expert. Wed, 28 Nov 2018 22:10:31 +0000 en-US hourly 1 https://wordpress.org/?v=4.8.8 http://www.littlebigextra.com/wp-content/uploads/2023/04/cropped-logo-32x32.png SpringBoot – Little Big Extra http://www.littlebigextra.com 32 32 How to enable communication over https between 2 spring boot applications using self signed certificate http://www.littlebigextra.com/how-to-enable-communication-over-https-between-2-spring-boot-applications-using-self-signed-certificate/ http://www.littlebigextra.com/how-to-enable-communication-over-https-between-2-spring-boot-applications-using-self-signed-certificate/#respond Wed, 08 Aug 2018 15:00:54 +0000 http://www.littlebigextra.com/?p=1263 How to enable communication over https between 2 spring boot applications using self signed certificate Introduction In this tutorial, we will try to cover how we can enable HTTPS communication over 2 Spring boot applications. HTTPS was developed for exchanging confidential information in a secured manner by making use of encryption using public and private keys in […]

The post How to enable communication over https between 2 spring boot applications using self signed certificate appeared first on Little Big Extra.

]]>
Share this article on

How to enable communication over https between 2 spring boot applications using self signed certificate

Introduction


In this tutorial, we will try to cover how we can enable HTTPS communication over 2 Spring boot applications. HTTPS was developed for exchanging confidential information in a secured manner by making use of encryption using public and private keys in order to prevent unauthorized access.

In the production environment, you will need to install a  certificate issued by a certificate authority (CA) which will validate identity and then and issue certificates. CA certificates contain a public key corresponding to a private key. The CA owns the private key and uses it to sign the certificates it issues. Certificates help prevent the use of fake public keys for impersonation.

However, CA-signed certificates might not be available in the lower environments like DEV or for local testing, in this case, you might want to establish that your API’s are able to talk over HTTPS and this is where you can make use of the self-signed certificate. 

Generating a self-signed certificate

We will use a self-signed certificate, to generate one we will need OpenSSL installed on our machine. In MacOs and Linux machines it is preinstalled, however, in windows you have to install it. Keytool can also be used to generate the self-signed certificates

    • You can use below command to generate a self-signed certificate and private key. Also, note that the CN (the Common name is localhost) as we will be running the application on localhost. If you want to run on a domain name you can either replace the CN name with Domain name or use Subject Alt Names to use multiple domains. Read here —> how to

 

  • Generate Public and Private keys
    openssl req -x509 -nodes -newkey rsa:2048 -keyout private.key -out selfsigned.pem -subj '/C=gb/ST=XX/L=XX/O=XX/OU=XX/CN=localhost/emailAddress=postmaster@example.com' -days 365

    The above command should generate set of public and private keys. The private key will be generated in a file called private.key and the public key or certificate will be generated in a file called selfsigned.pem.

    Also please note that above command also defines the country, state, location, organization name for simplification only XX has been added and the validity for above certificate is for a year which is controlled by ‘-days 365’. Feel free to change as per your needs.

  • Check if the generated PEM file is correct

    openssl x509 -in selfsigned.pem -text -noout

    If the certificate has been generated successfully, then basically above command should generate something like this, basically listing out the expiry date, the signature algorithm etc.

    Certificate:
        Data:
            Version: 1 (0x0)
            Serial Number: 10095699467019317110 (0x8c1b212d0ac96f76)
        Signature Algorithm: sha256WithRSAEncryption
            Issuer: C=gb, ST=XX, L=XX, O=XX, OU=XX, CN=loclhost/emailAddress=postmaster@example.com
            Validity
                Not Before: Jun 27 10:52:32 2018 GMT
                Not After : Jun 27 10:52:32 2019 GMT
            Subject: C=gb, ST=XX, L=XX, O=XX, OU=XX, CN=loclhost/emailAddress=postmaster@example.com
            Subject Public Key Info:

     

  • Combine your key and certificate in a PKCS#12 (P12) bundle: The PKCS#12 or PFX format is a binary format for storing the server certificate, any intermediate certificates, and the private key into a single encryptable file. The below command will generate a file called keystore.12

    openssl pkcs12 -export -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -export -in selfsigned.pem -inkey private.key -name selfsigned -out keystore.p12

     

  • Create a JKS from self-signed PEM: To implement X.509 authentication in a Spring application, we’ll first create a keystore in the Java Key-Store (JKS) format.

    keytool -importkeystore -srcstoretype PKCS12 -srckeystore keystore.p12 -destkeystore keystore.jks -deststoretype pkcs12

     

Adding the Keystore.jks in the Spring boot application

Add the following configuration to your spring boot application.yaml file and copy the above-generated keystore.jks file in src/main/resources folder

server:
  ssl:
    key-store-type: PKCS12
    key-store: 'classpath:keystore.jks'
    key-store-password: changeit
    key-alias: selfsigned

 

Now restart your application and see if you can see something in the logs ” Tomcat started on port(s): 8080 (https) with context path.. ”

This confirms that application will work only on https and not on http.

Calling from one Spring Boot application to another

Considering the above changes went well and both the Spring boot application has started and run on different ports with HTTPS enabled (server.port: port_number property can be used to configure different port numbers)

To call the other spring Boot application all we need is change the URL to use ‘https’

You can use RestTemplate to make a call

@Autowired
RestTemplate restTemplate;

void someRandomFunction(){
restTemplate.getForObject("https://localhost:8090/SpringBootApp1", Response.class)
}

 

If you get the below exception

org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://localhost:8100/customer/session/1b63e4b8-a91b-4742-b70a-8f113271212": sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

If you get SSL Handshake exception

****javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names present
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)

The post How to enable communication over https between 2 spring boot applications using self signed certificate appeared first on Little Big Extra.

]]>
http://www.littlebigextra.com/how-to-enable-communication-over-https-between-2-spring-boot-applications-using-self-signed-certificate/feed/ 0
Part-2: Authorising user using Spring Social (Google, Facebook, LinkedIn) and Spring Security http://www.littlebigextra.com/part-2-authorising-user-using-spring-social-google-facebook-linkedin-spring-security/ http://www.littlebigextra.com/part-2-authorising-user-using-spring-social-google-facebook-linkedin-spring-security/#comments Mon, 04 Dec 2023 12:20:52 +0000 http://littlebigextra.com/?p=1204 Part-2: Authorising user using Spring Social (Google, FaceBook and LinkedIn) and Spring Security   Introduction In the last part, I had demonstrated how we can use spring-social to authorize user using Facebook, Google and LinkedIn API’s. If you have not read the last part, I would request you to have a look and then come […]

The post Part-2: Authorising user using Spring Social (Google, Facebook, LinkedIn) and Spring Security appeared first on Little Big Extra.

]]>
Share this article on

Part-2: Authorising user using Spring Social (Google, FaceBook and LinkedIn) and Spring Security

 

Introduction

In the last part, I had demonstrated how we can use spring-social to authorize user using Facebook, Google and LinkedIn API’s. If you have not read the last part, I would request you to have a look and then come back to this part.

In this part, I am going to use spring security to allow only logged in users or authenticated users to navigate to secure pages, any user attempting to go to secure pages will be redirected to the Login page for authentication.
Once the user is authenticated, we will save his details to in-memory DB and then the user can log out and log in again.

Spring Security framework provides both authentication and authorization feature for applications. It also helps in preventing attacks like session fixation, clickjacking, cross-site request forgery, etc and good thing is that it can be customized easily to fit in different use cases.
In this tutorial, we will add spring security with spring social API to register users and then add the log on and log out functionality.

Step 1 – Adding Maven dependencies

The first step to start will be adding maven dependencies for Spring-security and also for thymeleaf-extras-spring security for using spring-security tags for displaying logged in user and roles etc on pages.
Add the following dependencies to the POM.xml

<dependency>
		        <groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-config</artifactId>
		</dependency>
		<dependency>
      	               <groupId>org.thymeleaf.extras</groupId>
                       <artifactId>thymeleaf-extras-springsecurity4</artifactId>
   	      </dependency>

Step 2 – Registering user on site

When logging on to social networking platforms, we didn’t need any form as we fetch the user details through the API. However, to register a user we will need a simple form to capture their details. We will create a view called registration.html under src/main/resources/templates/registration.html.
This form will have server-side validation and minimal CSS/JS


Source code of Registration page is as below

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Login</title>
<meta name="description" content="" />
<meta name="viewport" content="width=device-width" />
<base href="/" />
<link rel="stylesheet" type="text/css" href="/webjars/bootstrap/css/bootstrap.min.css" />
<script type="text/javascript" src="/webjars/jquery/jquery.min.js"></script>
<script type="text/javascript" src="/webjars/bootstrap/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="/webjars/font-awesome/css/font-awesome.min.css"></link>
</head>

<body>
	<div class="container" style="width:80%">
	<h1>Registration Page</h1>
	<br />
		<form action="#" th:action="@{/registration}" th:object="${userBean}" method="post" >
			<div class="form-group" >
				<label for="email" class="control-label col-sm-2">Email*</label>:: <input type="text" th:field="*{email}"  placeholder="Enter email"/>
				<div style="width:33%"  th:if="${#fields.hasErrors('email')}" th:errors="*{email}" class="alert alert-danger">Email Error</div>
			</div>
			<div class="form-group">
				<label for="firstName" class="control-label col-sm-2">First Name*</label>:: <input type="text" th:field="*{firstName}" />
				<div style="width:33%" th:if="${#fields.hasErrors('firstName')}" th:errors="*{firstName}" class="alert alert-danger">FirstName Error</div>
			</div>
			<div class="form-group">
				<label for="lastName" class="control-label col-sm-2">Last Name*</label>:: <input type="text" th:field="*{lastName}" />
				<div style="width:33%" th:if="${#fields.hasErrors('lastName')}" th:errors="*{lastName}" class="alert alert-danger">LastName Error</div>
			</div>
			<div class="form-group">
				<label for="password" class="control-label col-sm-2">Password*</label>:: <input type="text" th:field="*{password}" />
				<div style="width:33%" th:if="${#fields.hasErrors('password')}" th:errors="*{password}" class="alert alert-danger">Password Error</div>
			</div>
			<div class="form-group">
				<label for="passwordConfirm" class="control-label col-sm-2">Confirm Password*</label>:: <input type="text" th:field="*{passwordConfirm}" />
				<div style="width:33%" th:if="${#fields.hasErrors('passwordConfirm')}" th:errors="*{passwordConfirm}" class="alert alert-danger">Password Error</div>
			</div>
			<div class="form-group">
				<label for="title" class="control-label col-sm-2">Title</label>:: <select th:field="*{title}">
					<option value="Mr" th:text="Mr"></option>
					<option value="Mrs" th:text="Mrs"></option>
				</select>
				<div th:if="${#fields.hasErrors('title')}" th:errors="*{title}">Title Error</div>
			</div>
			<div class="form-group">
				<label for="country" class="control-label col-sm-2">Country</label>:: <select th:field="*{country}">
					<option value="India" th:text="India"></option>
					<option value="UK" th:text="UK"></option>
					<option value="US" th:text="US"></option>
					<option value="Japan" th:text="Japan"></option>
				</select>
				<div th:if="${#fields.hasErrors('country')}" th:errors="*{country}" class="alert alert-danger">Country Error</div>
			</div>
			<input type="hidden" name="provider"  value="registration" />
			<div class="form-group">
				<button type="submit" class="btn btn-primary">Register</button>
			</div>
		</form>

	</div>
</body>
</html>

Modifying the Controller

To serve this Page, we will modify the existing Login controller

@GetMapping("/registration")
    public String showRegistration(UserBean userBean) {
	return "registration";
    }

Modifying the Login Page

Now let’s modify the login page and add the registration link on the home page, also we will add username and password fields so once the user is registered they can also log in.

This HTML fragment will add a username/password field along with an error message, in case of the user not found.

<form th:action="@{/login}" method="post" style="display: inline">
			<label for="username">Username</label>: <input type="text" id="username" name="username" autofocus="autofocus" /> <br />
			<label for="password">Password</label>: <input type="password" id="password" name="password" /> <br />
			<p th:if="${loginError}" class="alert alert-danger">Wrong email or password combination</p>
			<button type="submit" class="btn btn-primary">
				<span class="fa fa-user"></span>Login
			</button>
		</form>

 

Also, let’s add another code fragment which is to display the Logged In user, the role assigned and a Logout button

<div th:fragment="logout" class="logout" sec:authorize="isAuthenticated()">
			Logged in user: <b><span sec:authentication="name"></span></b> | Roles: <b><span sec:authentication="authorities"></span></b>
				<form action="#" th:action="@{/logout}" method="post">
			       <button type="submit"  class="btn btn-danger btn-sm"
			       <span class="glyphicon glyphicon-log-out"></span>
			        Log out</button>
				</form>
		</div>

 

We will also need to csrf token to our existing forms for Google, Facebook and LinkedIn

<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />

This is how the Complete login.html looks like.

Login Page

Source code of login.html

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Login</title>
<meta name="description" content="" />
<meta name="viewport" content="width=device-width" />
<base href="/" />
<link rel="stylesheet" type="text/css" href="/webjars/bootstrap/css/bootstrap.min.css" />
<script type="text/javascript" src="/webjars/jquery/jquery.min.js"></script>
<script type="text/javascript" src="/webjars/bootstrap/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="/webjars/font-awesome/css/font-awesome.min.css"></link>
</head>

<body>

	<div class="container">
		
		<div th:fragment="logout" class="logout" sec:authorize="isAuthenticated()">
			Logged in user: <b><span sec:authentication="name"></span></b> | Roles: <b><span sec:authentication="authorities"></span></b>
				<form action="#" th:action="@{/logout}" method="post">
			       <button type="submit"  class="btn btn-danger btn-sm">
			       <span class="glyphicon glyphicon-log-out"></span>
			        Log out</button>
				</form>
		</div>
		<br/>
		
		<h1>Login Using</h1>

		<form th:action="@{/login}" method="post" style="display: inline">
			<label for="username">Email   </label> : <input type="text" id="username" name="username" autofocus="autofocus" placeholder="Enter email"/> <br />
			<label for="password">Password</label>: <input type="password" id="password" name="password" /> <br />
			<p th:if="${loginError}" class="alert alert-danger">Wrong email or password combination</p>
			<button type="submit" class="btn btn-primary">
				<span class="fa fa-user"></span>Login
			</button>
		</form>
		
		<form action="/connect/google" method="POST" style="display: inline">
			<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" /> 
			<input type="hidden" name="scope" value="profile email" />
			<button type="submit" class="btn btn-danger">
				Google <span class="fa fa-google-plus"></span>
			</button>
		</form>

		<form action="/connect/facebook" method="POST" style="display: inline">
			<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" /> 
			<input type="hidden" name="scope" value="public_profile,email" />
			<button type="submit" class="btn btn-primary">
				Facebook <span class="fa fa-facebook"></span>
			</button>
		</form>

		<form action="/connect/linkedin" method="POST" style="display: inline">
		<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" /> 
			<input type="hidden" name="scope"
				value="r_basicprofile,r_emailaddress" />
			<button type="submit" class="btn btn-primary">
				LinkedIn <span class="fa fa-linkedin"></span>
			</button>
		</form>
		<br />
		<h3>
			<p class="bg-important">
				<a href="/registration" th:href="@{/registration}">Create Account</a>
			</p>
		</h3>
	</div>
</body>
</html>

Step 3 – Saving User to Database

Once the user is authenticated, we will need to save their details in a database. So we will use the annotations like @Entity and @Table to create an in-memory database(HSQLDB) and tables if they don’t exist. The DB details can be easily configured in application.properties,also the DB type can also be changed easily.
We will use the hibernate validator annotations @NotNull,@Size to make sure that input fields are validated on the server side before they can be, you can add client-side javascript if that suits.

package com.login.model;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.Email;

@Entity(name = "user")
@Table(name = "user")
public class UserBean implements Serializable{
	
	private static final long serialVersionUID = 1L;
	
	@NotNull(message = "Email  cannot be empty")
	@Email(message = "Email Format is not valid")
	@Size(min = 3, max = 30, message = "Email can not be empty")
	@Id
	private String email;
	
	@NotNull(message = "First Name cannot be empty")
	@Size(min = 3, max = 30, message = "First Name cannot be less than 3 characters")
	private String firstName;

	@NotNull(message = "Last Name cannot be empty")
	@Size(min = 3, max = 30, message = "Last Name cannot be less than 3 characters")
	private String lastName;

	private String title;
	private String country;
	private String password;
	@Transient
	private String passwordConfirm;	
	private String provider;
	private String image;

	......getter/setter methods here ...

}

Saving the Bean using JPA Repository

We will be using to retrieve user details and save them.
Now we will create a new interface called UserRepository in package com.login.repository this interface will extend the JPARespository<T, ID> where T is UserBean in our Case and ID is the email(primary key).
We will define the abstract method findByEmail by passing email which has been defined as a primary key in UserBean class. To get the UserBean for a particular method all we need to do is inject the UserRepository and call findByemail method()

package com.login.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import com.login.model.UserBean;

public interface UserRepository extends JpaRepository<UserBean, String> {

    	UserBean findByEmail(String email);

}

The key advantage of using Spring Data is that it makes virtually our code DAO implementation-free, only above interface will be able to save and retrieve user details.

Step 4 – Adding the Spring Security

This is the crux of this tutorial, we will use the spring security to define which URL’s can be accessed only by insecurely and which one can only be accessed by login user.

We will add a class called SecurityConfig to allow users to

  • Allow URLs which start with CSS/** and /connect** to be accessed by all users
  • Allow /secure/* URL to be accessed only by logged in User
  • If any secure/* is accessed by unauthenticated user, redirect him to login page
  • In case of unsuccessful authentication, redirect user to /login-error
  • Add logout functionality

package com.login.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

//@formatter:off
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	private UserDetailsService userDetailsService;

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests().antMatchers("/css/**", "/connect/**").permitAll()
				.antMatchers("/secure/**")
				.authenticated()
				.and()
				.formLogin()
				.loginPage("/login")
				.defaultSuccessUrl("/secure/user")
				.failureUrl("/login-error")
				.permitAll()
				.and()
				.logout()
				.permitAll();
	}
	
	@Bean
	public BCryptPasswordEncoder bCryptPasswordEncoder() {
		return new BCryptPasswordEncoder();
	}
	
	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
	}

}

// @formatter:on

As you might have noticed that we have added a bean for BCryptPasswordEncoder, this bean will be used for encrypting the password as hash, which is one of the safest technique to store passwords and decrypting hash is very tough ( Maybe not as tough as mining a BitCoin 🙂 )

Also, there is another method configureglobal(AuthenticationManagerBuilder auth) which basically defines that we have defined our own custom implementation of UserDetailsService, we will talk about it later.

Move user.html to secure/user.html

Since now we want our user.html to be only presented for logged in users we will move user.html from src/main/resources/templates to src/main/resources/templates/secure/user.html
Also, we will add the thymleaf authentication tags to display logged in Username and role.
This is how the complete user.html looks like, make sure it is in src/main/resources/templates/secure/user.html

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Login</title>
<meta name="description" content="" />
<meta name="viewport" content="width=device-width" />
<meta name="ctx" th:content="${#httpServletRequest.getContextPath()}" />
<base href="/" />
<link rel="stylesheet" type="text/css" href="/webjars/bootstrap/css/bootstrap.min.css" />
<script type="text/javascript" src="/webjars/jquery/jquery.min.js"></script>
<script type="text/javascript" src="/webjars/bootstrap/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="/webjars/font-awesome/css/font-awesome.min.css"></link>
</head>
<body>

	<div class="container">
		<h1>Secure Page</h1>
				<div th:fragment="logout" class="logout" sec:authorize="isAuthenticated()">
			Logged in user: <b><span sec:authentication="name"></span></b> | Roles: <b><span sec:authentication="authorities"></span></b>
				<form action="#" th:action="@{/logout}" method="post">
			       <button type="submit"  class="btn btn-danger btn-sm">
			       <span class="glyphicon glyphicon-log-out"></span>
			        Log out</button>
				</form>
		</div>

		<br/>
		<form th:object="${loggedInUser}" method="post">
			<div class="row">
				<label for="email">Email :</label>
				<span th:text="*{email}" />
			</div>
			<div class="row">
				<label for="firstName">Name:</label>
				 <span th:text="*{firstName}" /> <span th:text="*{lastName}" />
			</div>
			<div class="row">
				<label for="image">Image:</label>
				 <img th:attr="src=@{*{image}}" style="width: 150px; height: 150px;"/>
			</div>

		</form>
		<br />
		  <a href="/login" th:href="@{/login}" class="btn btn-info btn-lg">
          <span class="glyphicon glyphicon-chevron-left"></span> Login using  other social Providers
         </a>
		 
	</div>

</body>
</html>

Step 6 – Adding UserDetails service, our own implementation

This is the crucial step as would define here what to do when the user puts in his username/password combination.
If we want user authentication by a DAO class, we need to implement the UserDetailsService interface. This interface has loadUserByUsername() method which is used to validate the user, of course, we need to provide the implementation.

Remeber this method in Security config

@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
	}

Providing our own implementation of UserDetailsService

We will write the implementation of method loadUserByUsername.In this method, we will do couple of things

  • Find Username in DB, if not found throw an exception
  • If the user is found, login user and return the User object of type org.springframework.security.core.userdetails.User, spring will automatically update the Security context for us.

package com.login.security.service.impl;

import java.util.HashSet;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.login.model.UserBean;
import com.login.repository.UserRepository;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

	@Autowired
	private UserRepository userRepository;
	

	@Override
	@Transactional(readOnly = true)
	public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
		
		UserBean user = userRepository.findByEmail(email);
		 if (user == null) {
	            throw new UsernameNotFoundException("No user found with email: " + email);
	        }
		Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
		grantedAuthorities.add(new SimpleGrantedAuthority("LOGGED_USER"));
		return new User(user.getEmail(), user.getPassword(), grantedAuthorities);
		
		
	}

}

Step 7 – Setting Security context (auto login)

Once the user is logged in by social providers or by registering a user we need to update security context by setting the authentication

As per the spring API – “Authentication represents the token for an authentication request or for an authenticated principal once the request has been processed by the AuthenticationManager.authenticate(Authentication) method.
Once the request has been authenticated, the Authentication will usually be stored in a thread-local SecurityContext managed by the SecurityContextHolder by the authentication mechanism which is being used. An explicit authentication can be achieved, without using one of Spring Security’s authentication mechanisms, by creating an Authentication instance and using the code:

SecurityContextHolder.getContext().setAuthentication(authentication)

Which is exactly we are going to do in our method.

package com.login.autologin;

import java.util.HashSet;
import java.util.Set;

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import com.login.model.UserBean;

@Service
public class Autologin {

    
    public void setSecuritycontext(UserBean userForm) {
   	Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
   	grantedAuthorities.add(new SimpleGrantedAuthority(userForm.getProvider().toUpperCase()));
   	Authentication authentication = new UsernamePasswordAuthenticationToken(userForm.getEmail(), userForm.getPassword(), grantedAuthorities);
   	SecurityContextHolder.getContext().setAuthentication(authentication);
       }
}

Step 8 – Changing the Login controller

Since now we have most of the things in place, we need to add the controller so when the registration form is submitted,

  • We need to save the user details on DB
  • Update the security context and set the authentication object
  • Redirect user to secure page.

Also, since in our Security config, we defined a “/login-error” path, we will handle that too in the same controller.

@Autowired
    private UserRepository userRepository;

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    private Autologin autologin;

    @PostMapping("/registration")
    public String registerUser(HttpServletResponse httpServletResponse, Model model, @Valid UserBean userBean, BindingResult bindingResult) {
	if (bindingResult.hasErrors()) {
	    return "registration";
	}
	userBean.setProvider("REGISTRATION");
	// Save the details in DB
	if (StringUtils.isNotEmpty(userBean.getPassword())) {
	    userBean.setPassword(bCryptPasswordEncoder.encode(userBean.getPassword()));
	}
	userRepository.save(userBean);

	autologin.setSecuritycontext(userBean);

	model.addAttribute("loggedInUser", userBean);
	return "secure/user";
    }

    /** If we can't find a user/email combination */
    @RequestMapping("/login-error")
    public String loginError(Model model) {
	model.addAttribute("loginError", true);
	return "login";
    }

Step 9 – Modifying the Social Providers

In previous post we had created the FacebookProvider, GoogleProvider and LinkedInProvider now we need to make some changes in them so they

  • Save the user details on DB
  • Update the security context and set the authentication object
  • Redirect the user to secure page.

In our class BaseProvider.java, we will add saveUserDetails and autoLoginUser method

@Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    protected Autologin autologin;

    protected void saveUserDetails(UserBean userBean) {
	if (StringUtils.isNotEmpty(userBean.getPassword())) {
	    userBean.setPassword(bCryptPasswordEncoder.encode(userBean.getPassword()));
	}
	userRepository.save(userBean);

    }

    public void autoLoginUser(UserBean userBean) {
	autologin.setSecuritycontext(userBean);
    }

In our provider classes(FacebookProvider, GoogleProvider and LinkedInProvider) we just need to add the code to

    Save the details in DB
    baseProvider.saveUserDetails(userForm);
    Login the User
    baseProvider.autoLoginUser(userForm);
    and also return back the secure page
    return "secure/user"

 

You will need to do these changes in all 3 classes(GoogleProvider, FaceBookProvider and LinkedInProvider)

public String getLinkedInUserData(Model model, UserBean userForm) {

		ConnectionRepository connectionRepository = baseProvider.getConnectionRepository();
		if (connectionRepository.findPrimaryConnection(LinkedIn.class) == null) {
			return REDIRECT_LOGIN;
		}
		populateUserDetailsFromLinkedIn(userForm);
		//Save the details in DB
		baseProvider.saveUserDetails(userForm);
		
		//Login the User
		baseProvider.autoLoginUser(userForm);
			
		model.addAttribute("loggedInUser",userForm);
		return "secure/user";
		}

Step 10 – Controller for /secure URL

Remeber, we have added in our 

defaultSuccessUrl("/secure/user")
SecurityConfig, well this is the page where we want the user to redirect, once they are authenticated.

Also on user/secure.html, we have defined

th:object="${loggedInUser}"
this attribute also needs to be initialized once the user is logged in by security config. So the question is how do we initialize the
"${loggedInUser}"
model attribute. If we don’t initialise it we will get an error.
An easy way to fix this problem is to use annotation called @ModelAttribute
@ModelAttribute("loggedInUser")
. If this annotation has been used all the RequestMapping method in the controller will be called only after the annotated method.

We can define a method where we will get the Authentication object and then use that object to find the user details.

@ModelAttribute("loggedInUser")
    public void secure(Model model) {
	Authentication auth = SecurityContextHolder.getContext().getAuthentication();
	UserBean user = userRepository.findByEmail(auth.getName());
	model.addAttribute("loggedInUser", user);
    }

Also, we need to define the method for mapping

@GetMapping("/secure/user")
 as shown below. Since we need to initialize model attribute
${loggedInUser}
only for
@GetMapping("/secure/user")
we need to define it in a separate controller class.

package com.login.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;

import com.login.model.UserBean;
import com.login.repository.UserRepository;

@Controller
public class LoggedInUserController {

    @Autowired
    private UserRepository userRepository;

    @ModelAttribute("loggedInUser")
    public void secure(Model model) {
	Authentication auth = SecurityContextHolder.getContext().getAuthentication();
	UserBean user = userRepository.findByEmail(auth.getName());
	model.addAttribute("loggedInUser", user);
    }

    @GetMapping("/secure/user")
    public String securePage() {
	return "secure/user";
    }

}

Step 11 – Updating the properties file

Since we are using HSQLDB in this example and spring boot will configure most of the things for us, we don’t need to do more than defining a couple of properties for initializing the database. Add these properties in application.properties

spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true

Conclusion

Spring Social and Spring Security are very flexible and easily customizable for different use cases. They both can be used together to provide a seamless and smooth log in experience for users. The above code is just a step in explaining how both the offerings (Spring Social and Spring Security) can be used in unison.

For readers benefit, above code can be cloned from

This is how the project structure looks like

 

This is how the screen looks like after user is logged in, the logged in user and the roles are being displayed on top of screen. 

The post Part-2: Authorising user using Spring Social (Google, Facebook, LinkedIn) and Spring Security appeared first on Little Big Extra.

]]>
http://www.littlebigextra.com/part-2-authorising-user-using-spring-social-google-facebook-linkedin-spring-security/feed/ 2
Part -1 : Authorising user using Spring Social (Google, FaceBook and LinkedIn) and Spring Security http://www.littlebigextra.com/part-1-authorising-user-using-spring-social-google-facebook-and-linkedin-and-spring-security/ http://www.littlebigextra.com/part-1-authorising-user-using-spring-social-google-facebook-and-linkedin-and-spring-security/#comments Mon, 20 Nov 2023 14:30:21 +0000 http://littlebigextra.com/?p=1167 Part-1: Authorising user using Spring Social (Google, FaceBook and LinkedIn) Introduction Social Logins are becoming increasingly popular across web applications, they not only offer good user experience are safe and also saves the user from password fatigue. Imagine losing a customer because they can not log on to the application as they cannot remember a […]

The post Part -1 : Authorising user using Spring Social (Google, FaceBook and LinkedIn) and Spring Security appeared first on Little Big Extra.

]]>
Share this article on

Part-1: Authorising user using Spring Social (Google, FaceBook and LinkedIn)

Introduction

Social Logins are becoming increasingly popular across web applications, they not only offer good user experience are safe and also saves the user from password fatigue. Imagine losing a customer because they can not log on to the application as they cannot remember a password are not bothered to reset passwords etc. A social login is a kind of single sign-on where you use login information of a social network like Facebook, Twitter, Google+ to log on to a third website, instead of creating a new log-in account specially for that website.

Earlier I have written few blogs about Spring-Social features where I had written about few problems like no support for Google, only one user allowed by spring-social etc and also few exceptions which occur and then how to fix them.I thought of collating all the problems and writing a step by step tutorial explaining in detail, on how to register a user using spring social.

The main aim of this tutorial will be to integrate spring-security and spring-social together and create a web application where users can be registered either by

  • Registering their details
  • Google
  • Facebook
  • LinkedIn

In this first part of the tutorial, our aim will be to get data from spring-social and then display the details on the page, in the second part we will integrate the spring-security where we will ask the user to enter his details and then store on  DB.

Step 1- Maven Dependencies

Assuming that you know how to create a simple spring boot project, let us move on to add maven-dependencies required to run the project. If not, then you can create a spring-starter project and add thymleaf and web support.

Adding Spring-Social dependencies

The first step would be to add spring-social maven repositories, following  dependencies are  required

<dependency>
			<groupId>org.springframework.social</groupId>
			<artifactId>spring-social-core</artifactId>
			<version>2.0.0.M2</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.social</groupId>
			<artifactId>spring-social-config</artifactId>
			<version>2.0.0.M2</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.social</groupId>
			<artifactId>spring-social-facebook</artifactId>
			<version>3.0.0.M1</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.social</groupId>
			<artifactId>spring-social-linkedin</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.social</groupId>
			<artifactId>spring-social-google</artifactId>
			<version>1.0.0.RELEASE</version>
		</dependency>

In case you get the repository not available error, you might have to add the following repository to your pom.

<repositories>
		<repository>
			<id>alfresco-public</id>
			<url>https://artifacts.alfresco.com/nexus/content/groups/public</url>
		</repository>
	</repositories>

Adding Thymleaf, BootStrap, JQuery and Font-awesome dependencies

To make our web pages look nice we will add some Bootstrap CSS, Font-awesome and Jquery to them and also we will use thymleaf for HTML. Read Here if you want to know more in detail.

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			 <groupId>org.webjars</groupId>
			 <artifactId>jquery</artifactId>
			 <version>2.1.1</version>
		 </dependency>
		 <dependency>
			 <groupId>org.webjars</groupId>
			 <artifactId>bootstrap</artifactId>
			 <version>3.2.0</version>
		 </dependency>
		 <dependency>
			 <groupId>org.webjars</groupId>
			 <artifactId>webjars-locator</artifactId>
		 </dependency>
		 <dependency>
			 <groupId>org.webjars</groupId>
			 <artifactId>font-awesome</artifactId>
			 <version>4.7.0</version>
		 </dependency>

Complete POM

To avoid any mistakes, here is the complete POM.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.login</groupId>
	<artifactId>SpringLogin</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>SpringLogin</name>
	<description>Spring Login - Example POC</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.8.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.social</groupId>
			<artifactId>spring-social-core</artifactId>
			<version>2.0.0.M2</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.social</groupId>
			<artifactId>spring-social-config</artifactId>
			<version>2.0.0.M2</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.social</groupId>
			<artifactId>spring-social-facebook</artifactId>
			<version>3.0.0.M1</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.social</groupId>
			<artifactId>spring-social-linkedin</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.social</groupId>
			<artifactId>spring-social-google</artifactId>
			<version>1.0.0.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<!-- <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> 
			</dependency> -->
		<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib</artifactId>
			<version>3.1</version>
		</dependency>
		<dependency>
			<groupId>org.webjars</groupId>
			<artifactId>jquery</artifactId>
			<version>2.1.1</version>
		</dependency>
		<dependency>
			<groupId>org.webjars</groupId>
			<artifactId>bootstrap</artifactId>
			<version>3.2.0</version>
		</dependency>
		<dependency>
			<groupId>org.webjars</groupId>
			<artifactId>webjars-locator</artifactId>
		</dependency>
		<dependency>
			<groupId>org.webjars</groupId>
			<artifactId>font-awesome</artifactId>
			<version>4.7.0</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.hsqldb</groupId>
			<artifactId>hsqldb</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
		</dependency>

	</dependencies>
	<repositories>
		<repository>
			<id>alfresco-public</id>
			<url>https://artifacts.alfresco.com/nexus/content/groups/public</url>
		</repository>
	</repositories>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>

 

Step 2- Adding Login Page and Controller

Once the dependencies have been resolved be will create a View and Controller

Adding View

To start we will create a view which will have 3 buttons each for Google, Facebook and Login. When the user will click on any of them he will be asked for authorization for the selected provider, upon verification his details will be rendered on the page.

Create a file under src/main/resources/templates/login.html with the following content. Please note that this view has 3 different forms each for different provider

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Login</title>
<meta name="description" content="" />
<meta name="viewport" content="width=device-width" />
<base href="/" />
<link rel="stylesheet" type="text/css" href="/webjars/bootstrap/css/bootstrap.min.css" />
<script type="text/javascript" src="/webjars/jquery/jquery.min.js"></script>
<script type="text/javascript" src="/webjars/bootstrap/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="/webjars/font-awesome/css/font-awesome.min.css"></link>
</head>

<body>

	<div class="container">
		<h1>Login Using</h1>

		<form action="/connect/google" method="POST" style="display: inline">
			<input type="hidden" name="scope" value="profile email" />
			<button type="submit" class="btn btn-danger">
				Google <span class="fa fa-google-plus"></span>
			</button>
		</form>

		<form action="/connect/facebook" method="POST" style="display: inline">
			<input type="hidden" name="scope" value="public_profile,email" />
			<button type="submit" class="btn btn-primary">
				Facebook <span class="fa fa-facebook"></span>
			</button>
		</form>

		<form action="/connect/linkedin" method="POST" style="display: inline">
			<input type="hidden" name="scope"
				value="r_basicprofile,r_emailaddress" />
			<button type="submit" class="btn btn-primary">
				LinkedIn <span class="fa fa-linkedin"></span>
			</button>
		</form>
	</div>
</body>
</html>

Adding Controller

Let us create a controller class called LoginController in package com.login.controller with a simple method which will map the above page to URL / or /login.

@Controller
public class LoginController {

@RequestMapping(value = { "/","/login" })
	public String login() {
		return "login";
	}
}

Now run the above application and at this point, a page like this should appear and of course, it won’t do anything yet.

Step 3- Creating a POJO to show authorised user detail

Once we verify the user via our social provider, we will show the user details on another page. We can store these details in a POJO called UserBean.
Let us define a class called UserBean.java as shown below in package com.login.model

package com.login.model;

import java.beans.Transient;
import java.io.Serializable;

public class UserBean implements Serializable{
	
	private static final long serialVersionUID = 1L;
	private String firstName;
	private String lastName;
	private String email;
	private String title;
	private String country;
	private String password;
	private String passwordConfirm;	
	private String provider;
	private String image;
	
	
	public String getEmail() {
		return email;
	}

	public String getImage() {
	    return image;
	}

	public void setImage(String image) {
	    this.image = image;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	
	public String getPasswordConfirm() {
		return passwordConfirm;
	}

	public void setPasswordConfirm(String passwordConfirm) {
		this.passwordConfirm = passwordConfirm;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getCountry() {
		return country;
	}

	public void setCountry(String country) {
		this.country = country;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}


	public String getProvider() {
		return provider;
	}

	public void setProvider(String provider) {
		this.provider = provider;
	}

	 

}

Step 4 – Creating Social Media Providers

For Facebook, Google and LinkedIn we will create a Provider class which will be used to do authentication and save user details to the UserBean, which can be later displayed on the page. To start off with we will create a BaseProvider which will have a constructor where all the providers will be initialized.

This BaseProvider is created by injecting the Facebook, Google, LinkedIn and ConnectionRepository repository. These objects are a reference to Spring Social’s Facebook, Google, LinkedIn and ConnectionRepository API binding.

package com.login.social.providers;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.social.connect.ConnectionRepository;
import org.springframework.social.facebook.api.Facebook;
import org.springframework.social.google.api.Google;
import org.springframework.social.linkedin.api.LinkedIn;

@Configuration
@Scope(value = "request",  proxyMode = ScopedProxyMode.TARGET_CLASS)
public class BaseProvider {

	private Facebook facebook;
	private Google google;
	private LinkedIn linkedIn;
	private ConnectionRepository connectionRepository;
	
	public  BaseProvider(Facebook facebook,Google google,  LinkedIn linkedIn, ConnectionRepository connectionRepository) {
		this.facebook = facebook;
		this.connectionRepository = connectionRepository;
		this.google=google; 
		this.linkedIn= linkedIn;
	}

	public Facebook getFacebook() {
		return facebook;
	}

	public void setFacebook(Facebook facebook) {
		this.facebook = facebook;
	}

	public ConnectionRepository getConnectionRepository() {
		return connectionRepository;
	}

	public void setConnectionRepository(ConnectionRepository connectionRepository) {
		this.connectionRepository = connectionRepository;
	}

	public Google getGoogle() {
		return google;
	}

	public void setGoogle(Google google) {
		this.google = google;
	}

	public LinkedIn getLinkedIn() {
		return linkedIn;
	}

	public void setLinkedIn(LinkedIn linkedIn) {
		this.linkedIn = linkedIn;
	}
	
	

}

Now let us create provider class for each provider

Facebook Provider

We will use the below Facebook provider to authorize the user and then access Facebook Data. We will save the fetched user data into our UserBean.

package com.login.social.providers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.social.connect.ConnectionRepository;
import org.springframework.social.facebook.api.Facebook;
import org.springframework.social.facebook.api.User;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;

import com.login.model.UserBean;


@Service
public class FacebookProvider  {

	private static final String FACEBOOK = "facebook";
	private static final String REDIRECT_LOGIN = "redirect:/login";

    	@Autowired
    	BaseProvider baseProvider ;
    	

	public String getFacebookUserData(Model model, UserBean userForm) {

		ConnectionRepository connectionRepository = baseProvider.getConnectionRepository();
		if (connectionRepository.findPrimaryConnection(Facebook.class) == null) {
			return REDIRECT_LOGIN;
		}
		populateUserDetailsFromFacebook(userForm);
		model.addAttribute("loggedInUser",userForm);
		return "user";
	}

	protected void populateUserDetailsFromFacebook(UserBean userForm) {
		Facebook facebook = baseProvider.getFacebook();
		User user = facebook.userOperations().getUserProfile();
		userForm.setEmail(user.getEmail());
		userForm.setFirstName(user.getFirstName());
		userForm.setLastName(user.getLastName());
		userForm.setImage(user.getCover().getSource());
		userForm.setProvider(FACEBOOK);
	}

	 

}

Google Provider

We will use the below google provider to authorize the user and then access Google Data. We will save the fetched user data into our UserBean.

package com.login.social.providers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.social.connect.ConnectionRepository;
import org.springframework.social.google.api.Google;
import org.springframework.social.google.api.plus.Person;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;

import com.login.model.UserBean;

@Service
public class GoogleProvider   {

	private static final String REDIRECT_CONNECT_GOOGLE = "redirect:/login";
	private static final String GOOGLE = "google";

   	@Autowired
    	BaseProvider socialLoginBean ;


	public String getGoogleUserData(Model model, UserBean userForm) {

		ConnectionRepository connectionRepository = socialLoginBean.getConnectionRepository();
		if (connectionRepository.findPrimaryConnection(Google.class) == null) {
			return REDIRECT_CONNECT_GOOGLE;
		}

		populateUserDetailsFromGoogle(userForm);
		model.addAttribute("loggedInUser",userForm);
		return "user";
	}

	
	protected void populateUserDetailsFromGoogle(UserBean userform) {
		Google google = socialLoginBean.getGoogle();
		Person googleUser = google.plusOperations().getGoogleProfile();
		userform.setEmail(googleUser.getAccountEmail());
		userform.setFirstName(googleUser.getGivenName());
		userform.setLastName(googleUser.getFamilyName());
		userform.setImage(googleUser.getImageUrl());
		userform.setProvider(GOOGLE);
	}

}

LinkedIn Provider

We will use the below LinkedIn provider to authorize the user and then accessLinkedIn Data. We will save the fetched user data into our UserBean.

package com.login.social.providers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.social.connect.ConnectionRepository;
import org.springframework.social.linkedin.api.LinkedIn;
import org.springframework.social.linkedin.api.LinkedInProfileFull;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;

import com.login.model.UserBean;

@Service
public class LinkedInProvider  {

	private static final String LINKED_IN = "linkedIn";
	
	private static final String REDIRECT_LOGIN = "redirect:/login";

  	@Autowired
    	BaseProvider socialLoginBean ;

	public String getLinkedInUserData(Model model, UserBean userForm) {

		ConnectionRepository connectionRepository = socialLoginBean.getConnectionRepository();
		if (connectionRepository.findPrimaryConnection(LinkedIn.class) == null) {
			return REDIRECT_LOGIN;
		}
		populateUserDetailsFromLinkedIn(userForm);
		model.addAttribute("loggedInUser",userForm);
		return "user";
	}
	
	private void populateUserDetailsFromLinkedIn(UserBean userForm) {
		LinkedIn linkedIn = socialLoginBean.getLinkedIn();
		LinkedInProfileFull linkedInUser = linkedIn.profileOperations().getUserProfileFull();
		userForm.setEmail(linkedInUser.getEmailAddress());
		userForm.setFirstName(linkedInUser.getFirstName());
		userForm.setLastName(linkedInUser.getLastName());
		userForm.setImage(linkedInUser.getProfilePictureUrl());
		userForm.setProvider(LINKED_IN);
	}

}

Step 5 – Fixing some issues before we can run – Adding Google Support

If you would have noticed by now, spring social doesn’t support Google so to enable autoconfiguration of spring-social-google we need to

Add a GoogleAutoConfiguration Class

Spring social do have a spring-social-google project but it doesn’t have autoconfiguration for Google. So google authorization doesn’t work with spring boot autoconfigure straight away.

To enable autoconfigure of spring-social-google we need to

  • Add a GoogleAutoConfiguration
  • Add GoogleProperties

FacebookAutoConfiguration class you should be able to find it either in org.springframework.boot.autoconfigure.social package in spring-autoconfigure.jar does the autoconfiguration for Facebook, the cheat sheet or the trick would be to copy this File and replace Facebook with Google to enable GoogleAutoConfiguration

Alternatively, copy the below class and put in some package, make sure it is available in classpath(src/main/java or inside another source folder)

package com.login.config.google;

import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.social.SocialAutoConfigurerAdapter;
import org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration;
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.social.config.annotation.EnableSocial;
import org.springframework.social.config.annotation.SocialConfigurerAdapter;
import org.springframework.social.connect.Connection;
import org.springframework.social.connect.ConnectionFactory;
import org.springframework.social.connect.ConnectionRepository;
import org.springframework.social.connect.web.GenericConnectionStatusView;
import org.springframework.social.google.api.Google;
import org.springframework.social.google.connect.GoogleConnectionFactory;


@Configuration
@ConditionalOnClass({ SocialConfigurerAdapter.class, GoogleConnectionFactory.class })
@ConditionalOnProperty(prefix = "spring.social.google", name = "app-id")
@AutoConfigureBefore(SocialWebAutoConfiguration.class)
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
public class GoogleAutoConfiguration {

	@Configuration
	@EnableSocial
	@EnableConfigurationProperties(GoogleProperties.class)
	@ConditionalOnWebApplication
	protected static class GoogleConfigurerAdapter extends SocialAutoConfigurerAdapter {

		private final GoogleProperties properties;

		protected GoogleConfigurerAdapter(GoogleProperties properties) {
			this.properties = properties;
		}

		@Bean
		@ConditionalOnMissingBean(Google.class)
		@Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
		public Google google(ConnectionRepository repository) {
			Connection<Google> connection = repository.findPrimaryConnection(Google.class);
			return connection != null ? connection.getApi() : null;
		}

		@Bean(name = { "connect/googleConnect", "connect/googleConnected" })
		@ConditionalOnProperty(prefix = "spring.social", name = "auto-connection-views")
		public GenericConnectionStatusView googleConnectView() {
			return new GenericConnectionStatusView("google", "Google");
		}

		@Override
		protected ConnectionFactory<?> createConnectionFactory() {
			return new GoogleConnectionFactory(this.properties.getAppId(), this.properties.getAppSecret());
		}

	}

}

 

Add GoogleProperties

In the same package add the below class, this is needed so when we add secret keys in properties file for google. We wont see any error.

package com.login.config.google;

import org.springframework.boot.autoconfigure.social.SocialProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "spring.social.google")

public class GoogleProperties extends SocialProperties{

	
}

Read Here: How to access Google data using spring-social

Step 6- Fixing some issues before we can run – Changing the default spring social redirect face flow

Spring Social is quick and easy to start but it needs some configuring before it can be used for production. The default flow for

The Views are predefined so the user flow is login.html -> connect/facebookConnected.html by default, irrespective of what our submit URL is, the facebook will override the flow and redirect you to connect/facebookConnected.html.

Read Here: How to change the default spring social redirect page flow 

We will add a ChangeDefaultFlowController  which will override the connectedView method and redirect the flow to “/facebook”, “/google” or “/LinkedIn”

package com.login.controller;

import org.springframework.social.connect.ConnectionFactoryLocator;
import org.springframework.social.connect.ConnectionRepository;
import org.springframework.social.connect.web.ConnectController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;


@Controller
@RequestMapping("/connect")
public class ChangeDefaultFlowController extends ConnectController {

	public ChangeDefaultFlowController(ConnectionFactoryLocator connectionFactoryLocator,
			ConnectionRepository connectionRepository) {
		super(connectionFactoryLocator, connectionRepository);
	}
	
	@Override
    protected String connectedView(String providerId) {
        return "redirect:/"+providerId;
    }

}

 

Step 7 – Fixing some issues before we can run – Allowing Multiple Users to Login

If you test the Spring Facebook example, accessing FB data you will realise that it only supports one user. So when the first users log in to Facebook, only his details will be shared across all new sessions/users and they won’t be asked for any kind of authentication. One of the forum says that this example is supposed to demonstrate what can be done and is not intended for production use.

Read Here: Spring Social Facebook Authentication Example for multiple users 

To fix this problem you need to override a method which always returns a string called “anonymous”.The solution is to override the “anonymous�? as the UserId for each new user/session. So for each session, we can simply return a SessionID, however, it may not be unique enough to identify users, especially if it’sh being cached or stored somewhere in a connection database.
Using a Universally Unique Identifier(UUID) would be a safer bet.So we will store a new UUID in session so it persists between different requests but is alive only till the session is valid. See the below method which does the trick.

package com.login.identifier;

import java.util.UUID;

import org.springframework.context.annotation.Configuration;
import org.springframework.social.UserIdSource;
import org.springframework.social.config.annotation.SocialConfigurerAdapter;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;


@Configuration
public class SessionIdentifier extends SocialConfigurerAdapter
{

    @Override
    public UserIdSource getUserIdSource() {
        return new SessionIdUserIdSource();
    }

    private static final class SessionIdUserIdSource implements UserIdSource {
    	@Override
        public String getUserId() {
            RequestAttributes request = RequestContextHolder.currentRequestAttributes();
            String uuid = (String) request.getAttribute("_socialUserUUID", RequestAttributes.SCOPE_SESSION);
            if (uuid == null) {
                uuid = UUID.randomUUID().toString();
                request.setAttribute("_socialUserUUID", uuid, RequestAttributes.SCOPE_SESSION);
            }
            return uuid;
        }
    }
}

 

Step 8 – Updating the LoginController

Now since we have added all the fixes, its time to update the controller so our view can submit the forms to Controller

package com.login.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.login.model.UserBean;
import com.login.social.providers.FacebookProvider;
import com.login.social.providers.GoogleProvider;
import com.login.social.providers.LinkedInProvider;

@Controller
public class LoginController {

	@Autowired 
	FacebookProvider facebookProvider;
	
	@Autowired 
	GoogleProvider googleProvider;

	@Autowired 
	LinkedInProvider linkedInProvider;

	@RequestMapping(value = "/facebook", method = RequestMethod.GET)
	public String loginToFacebook(Model model) {
		return facebookProvider.getFacebookUserData(model, new UserBean());
	}

	@RequestMapping(value = "/google", method = RequestMethod.GET)
	public String loginToGoogle(Model model) {
		return googleProvider.getGoogleUserData(model, new UserBean());
	}

	@RequestMapping(value = "/linkedin", method = RequestMethod.GET)
	public String helloFacebook(Model model) {
		return linkedInProvider.getLinkedInUserData(model, new UserBean());
	}
	
	@RequestMapping(value = { "/","/login" })
	public String login() {
		return "login";
	}

}

Step 9 – Adding Spring properties

Assuming that you know how to register the API and public/private keys on Google/FB and LinkedIn for this example purpose you can use the below properties file.
Also, notice that server starts on port 3000(don’t change that, since the URL registered with these keys is localhost:3000

 

spring.social.facebook.appId=384261248599251
spring.social.facebook.appSecret=fd7fa1c5f5a267f463263a0ce7ff2025

spring.social.linkedin.app-id=771mrzk94hye1w
spring.social.linkedin.app-secret=iIJFgBf9lCb18zYe

spring.social.google.appId=12894100090-tqso3lih5o42isneort886la2pesafmp.apps.googleusercontent.com
spring.social.google.appSecret=9xfU16efvxQ-BTMsXT9wOLpw

server.port:3000

This is how the project structure will look like

Step 10 – User Details on page

To show the authenticated user on the page, we will display the UserBean using thymleaf. Add the below html page under src/main/resources/static/ as user.html

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Login</title>
<meta name="description" content="" />
<meta name="viewport" content="width=device-width" />
<meta name="ctx" th:content="${#httpServletRequest.getContextPath()}" />
<base href="/" />
<link rel="stylesheet" type="text/css" href="/webjars/bootstrap/css/bootstrap.min.css" />
<script type="text/javascript" src="/webjars/jquery/jquery.min.js"></script>
<script type="text/javascript" src="/webjars/bootstrap/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="/webjars/font-awesome/css/font-awesome.min.css"></link>
</head>
<body>



	<div class="container">
		<br /><br /><br />
		<form th:object="${loggedInUser}" method="post">
			<div class="row">
				<label for="username">Username:</label>
				<span th:text="${loggedInUser.email}" />
			</div>
			<div class="row">
				<label for="firstName">Name:</label>
				 <span th:text="*{firstName}" /> <span th:text="*{lastName}" />
			</div>
			<div class="row">
				<label for="image">Name:</label>
				 <img th:attr="src=@{*{image}}" style="width: 150px; height: 150px;"/>
			</div>

		</form>
		<br />
		  <a href="/login" th:href="@{/login}" class="btn btn-info btn-lg">
          <span class="glyphicon glyphicon-chevron-left"></span> Login using  other social Providers
         </a>
		 
	</div>

</body>
</html>

Now run the Project and access the application on http://localhost:3000/login.

You should be greeted by an authentication popup depending upon your provider selected and then you should be redirected to the page where your username, name, profile image will be displayed as below.

Conclusion

Spring Social API helps us in implementing an authentication mechanism with social providers. It is easy to use and we have seen how to configure it to tailor it to our needs.

Above code can be cloned from

In the next part we will use spring-security to register users and then only allow logged in users to navigate to secure pages. The link has been provided below for second part.

 

The post Part -1 : Authorising user using Spring Social (Google, FaceBook and LinkedIn) and Spring Security appeared first on Little Big Extra.

]]>
http://www.littlebigextra.com/part-1-authorising-user-using-spring-social-google-facebook-and-linkedin-and-spring-security/feed/ 6
How to use Spring Profiles with Docker Containers http://www.littlebigextra.com/use-spring-profiles-docker-containers/ http://www.littlebigextra.com/use-spring-profiles-docker-containers/#comments Fri, 11 Aug 2023 10:18:16 +0000 http://littlebigextra.com/?p=1089   How to use Spring Profiles with Docker Containers Introduction Spring Profiles are an effective way of implementing environment independent code. The properties file or @Beans can be selected dynamically at run time based on the profile injected. Assuming that you are quite familiar with the spring profiles and looking for injecting profiles in a […]

The post How to use Spring Profiles with Docker Containers appeared first on Little Big Extra.

]]>
Share this article on

 

How to use Spring Profiles with Docker Containers

Introduction

Spring Profiles are an effective way of implementing environment independent code. The properties file or @Beans can be selected dynamically at run time based on the profile injected.
Assuming that you are quite familiar with the spring profiles and looking for injecting profiles in a Docker environment. There are couple of ways of doing it namely

 

 

  • Passing Spring Profile in Dockerfile
  • Passing Spring Profile in Docker run command
  • Passing Spring Profile in DockerCompose

In this tutorial, I will try to capture all these 3 scenarios.

Read Here: How to create Docker image of Standalone Spring MVC project

Passing Spring Profile in a Dockerfile

From command prompt of your system, any spring boot application can be run with “java -jar” command.The profiles need to be passed as an argument like this “-Dspring.profiles.active=dev“. For Spring MVC applications other 2 below methods will work fine.

java -Djava.security.egd=file:/dev/./urandom -Dspring.profiles.active=dev -jar rest-api.jar

Similarly, when using dockerfile we need to pass the profile as an argument, have a look at one of the Dockerfile for creating a spring boot docker image

Below an example on spring boot project dockerfile

FROM java:8
ADD target/my-api.jar rest-api.jar
RUN bash -c 'touch /pegasus.jar'
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom","-Dspring.profiles.active=dev","-jar","/rest-api.jar"]

Pay attention to the last line ENTRYPOINT, in this line we are passing the java command to execute the jar file and all arguments have been passed as comma separated values. “-Dspring.profiles.active=dev” is where we are passing the dev profile, you can replace dev with the profile name you want.

Passing Spring Profile in Docker run

You can also pass spring profile as an environment variable while using docker run command using the -e flag. The option -e “SPRING_PROFILES_ACTIVE=dev” will inject the dev profile to the Docker container.

docker run -d -p 8080:8080 -e "SPRING_PROFILES_ACTIVE=dev" --name rest-api dockerImage:latest

 

Passing Spring Profile in DockerCompose

If you are on DockerSwarm or using compose file for deploying docker images the Spring profile can be passed using the environment: tag in a docker-compose file, as shown below

version: "3"
services:
  rest-api:
     image: rest-api:0.0.1
     ports:
       - "8080:8080" 
     environment:
       - "SPRING_PROFILES_ACTIVE=dev"

 

The post How to use Spring Profiles with Docker Containers appeared first on Little Big Extra.

]]>
http://www.littlebigextra.com/use-spring-profiles-docker-containers/feed/ 3
Part 3 :Authorising user using Spring Social (Google, Facebook, LinkedIn) and Spring Security http://www.littlebigextra.com/part-3-authorising-user-using-spring-social-google-facebook-linkedin-and-spring-security/ http://www.littlebigextra.com/part-3-authorising-user-using-spring-social-google-facebook-linkedin-and-spring-security/#comments Wed, 09 Aug 2023 14:44:03 +0000 http://littlebigextra.com/?p=1250 Part-3: Authorising user using Spring Social (Google, Facebook, LinkedIn) and Spring Security Introduction In Part-1, We discussed how to authenticate with social providers like Facebook, Google, and LinkedIn. Along with that, we changed the default page flow for spring social, enabled it to be used by multiple users and provided support for Google. In Part-2, […]

The post Part 3 :Authorising user using Spring Social (Google, Facebook, LinkedIn) and Spring Security appeared first on Little Big Extra.

]]>
Share this article on

Part-3: Authorising user using Spring Social (Google, Facebook, LinkedIn) and Spring Security

Introduction

In Part-1, We discussed how to authenticate with social providers like Facebook, Google, and LinkedIn. Along with that, we changed the default page flow for spring social, enabled it to be used by multiple users and provided support for Google.
In Part-2, We used spring-security to allow only logged in users to see secure pages, also we added registration page to register users.

So what is in this tutorial

Well if you have read and run the application up to  Part-2 then let me tell you that there is a bug in the code. Also, there might be a case where social network providers may not send all the required data.

So, what is the bug?

Create an account using registration and then log out, log in again now using social provider(same email id). Now if you try to log in using the email/password combination, you will receive an error.

In Simple terms to replicate the above bug

  • Register the user, using create an account and then log out
  • Use the same email address and log in by a social provider and log out
  • Now try using the email/password combination to log in and it will give an error

It won’t work because when we logged in through social provider it basically overwrote the password with the blank.

Also, the social provider may not provide all the information

All social providers send back the data differently and its very possible they may not send all the fields which you want for e.g Facebook may not return country, while Google may not return Title.

So what will we be doing

We will do a couple of things in this tutorial the first being

  • Fix the bug, create a new method in UserRepository to save without password
  • Check if we have received all the data if no send the user to a new page to collect all the information.

Saving the User without password when logging through social providers

We will add a method in UserRepository Interface called saveWithoutPassword and in this method, we will save all fields except the password.
This way we will make sure that the passwords saved are not overwritten.

@Modifying
	@Transactional
	@Query("UPDATE user SET firstName = :firstName, lastName = :lastName, country = :country, image = :image "
			+ " WHERE email = :email")
	void saveWithoutPassword(@Param("firstName") String firstname, @Param("lastName") String lastname,
			@Param("country") String country, @Param("image") String image,
			@Param("email") String email);

Adding method in BaseProvider

In Base Provider class we will check if the password is empty, which indicates the user might have logged in from the Social provider so save all details except passwords by calling the saveWithoutPassword method.

protected void saveUserDetails(UserBean userBean) {
	if (StringUtils.isNotEmpty(userBean.getPassword())) {
	    userBean.setPassword(bCryptPasswordEncoder.encode(userBean.getPassword()));
	}
	userRepository.saveWithoutPassword(userBean.getFirstName(), userBean.getLastName(), userBean.getCountry(), userBean.getImage(), userBean.getEmail());

    }

Check if all information is available from Social Provider

Every Social Provider has some mandatory and not mandatory fields, which means they might not be capturing all the information. Also, some social providers may not provide all the information, which means that we should check if all information we need from our end is present and if absent ask the user to fill the missing information.

In BaseProvider class, we will add the method to check if all mandatory fields are not null and not blank.

protected boolean isAllInformationAvailable(UserBean userBean) {
	return StringUtils.isNotEmpty(userBean.getEmail()) &&
	StringUtils.isNotEmpty(userBean.getFirstName()) &&
	StringUtils.isNotEmpty(userBean.getLastName()) &&
	StringUtils.isNotEmpty(userBean.getTitle()) &&
	StringUtils.isNotEmpty(userBean.getCountry());
    }

and add the below condition in the method before saving, where we check if any information is missing then redirect the user to “incompleteInfo” page.

//Check if all Info has been collected
		if(!baseProvider.isAllInformationAvailable(userBean)) {
		    model.addAttribute("userBean", userBean);
		    return "incompleteInfo";
		}

the complete method will look like this, you will need to do same for all social providers(Facebook, Google, and LinkedIn). Below is an example of class FaceBookProvider method.

public String getFacebookUserData(Model model, UserBean userBean) {

		ConnectionRepository connectionRepository = baseProvider.getConnectionRepository();
		if (connectionRepository.findPrimaryConnection(Facebook.class) == null) {
			return REDIRECT_LOGIN;
		}
		//Populate the Bean
		populateUserDetailsFromFacebook(userBean);
		//Check if all Info has been collected
		if(!baseProvider.isAllInformationAvailable(userBean)) {
		    model.addAttribute("userBean", userBean);
		    return "incompleteInfo";
		}
		//Save the details in DB
		baseProvider.saveUserDetails(userBean);
		//Login the User
		baseProvider.autoLoginUser(userBean);
		model.addAttribute("loggedInUser",userBean);
		return "secure/user";
	}

Adding Incomplete Info

Add the incompleteInfo.html in src/main/resources/templates folder. Basically, in this HTML file using thymleaf constructs, we will check which fields of Userbean has not been populated and render the HTML fields where they are null.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Login</title>
<meta name="description" content="" />
<meta name="viewport" content="width=device-width" />
<base href="/" />
<link rel="stylesheet" type="text/css" href="/webjars/bootstrap/css/bootstrap.min.css" />
<script type="text/javascript" src="/webjars/jquery/jquery.min.js"></script>
<script type="text/javascript" src="/webjars/bootstrap/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="/webjars/font-awesome/css/font-awesome.min.css"></link>
</head>

<body>
 
	<div class="container">
	
	<h2>Sorry, but we could not find all the information so please fill the following fields</h2>
		<form th:action="@{/registration}" th:object="${userBean}" method="post">
			<table>
				<tr th:unless="${userBean.email}">
					<td>Email:</td>
					<td><input type="text" th:field="*{email}" /></td>
					<td th:if="${#fields.hasErrors('email')}" th:errors="*{email}">Name Error</td>
				</tr>
				<tr th:if="${userBean.email}">
					<input type="hidden" th:field="*{email}" />
				</tr>
				
				<tr th:unless="${userBean.title}">
					<td>Title:</td>
					<td><select th:field="*{title}">
							<option value="Mr" th:text="Mr"></option>
							<option value="Mrs" th:text="Mrs"></option>
					</select></td>
					<td th:if="${#fields.hasErrors('title')}" th:errors="*{title}">Title Error</td>
				</tr>
				<tr th:if="${userBean.title}">
					<input type="hidden" th:field="*{title}" />
				</tr>
				
				<tr th:unless="${userBean.firstName}">
					<td>Email:</td>
					<td><input type="text" th:field="*{firstName}" /></td>
					<td th:if="${#fields.hasErrors('firstName')}" th:errors="*{email}">Name Error</td>
				</tr>
				<tr th:if="${userBean.firstName}">
					<input type="hidden" th:field="*{firstName}" />
				</tr>
				
				<tr th:unless="${userBean.lastName}">
					<td>Email:</td>
					<td><input type="text" th:field="*{lastName}" /></td>
					<td th:if="${#fields.hasErrors('lastName')}" th:errors="*{lastName}">Name Error</td>
				</tr>
				<tr th:if="${userBean.lastName}">
					<input type="hidden" th:field="*{lastName}" />
				</tr>
				 
				<tr th:unless="${userBean.country}">
					<td>Country:</td>
					<td><select th:field="*{country}">
							<option value="India" th:text="India"></option>
							<option value="UK" th:text="UK"></option>
							<option value="US" th:text="US"></option>
							<option value="Iraq" th:text="Iraq"></option>
					</select></td>
					<td th:if="${#fields.hasErrors('country')}" th:errors="*{country}">Country Error</td>
				</tr>
				<tr th:if="${userBean.country}">
					<input type="hidden" th:field="*{country}" />
				</tr>
				<input type="hidden" th:field="*{password}" />
				<input type="hidden" th:field="*{passwordConfirm}"  />
				 
				<tr>
					<td><button type="submit">Submit</button></td>
				</tr>
			</table>
		</form>

	</div>
</body>
</html>

 

That’s all, we have successfully created a login application which integrates with the different social providers and also allows us to register new users.

 

The above code can be .

The post Part 3 :Authorising user using Spring Social (Google, Facebook, LinkedIn) and Spring Security appeared first on Little Big Extra.

]]>
http://www.littlebigextra.com/part-3-authorising-user-using-spring-social-google-facebook-linkedin-and-spring-security/feed/ 1
How to consume REST based web service in Spring BOOT http://www.littlebigextra.com/consume-rest-based-web-service-spring-boot/ http://www.littlebigextra.com/consume-rest-based-web-service-spring-boot/#comments Tue, 25 Apr 2023 15:08:39 +0000 http://littlebigextra.com/?p=907 How to consume REST based web service in Spring BOOT Introduction In my last tutorial I wrote about Consuming a secure SOAP based web service in Spring Boot application, In this tutorial, I will talk about consuming a simple unsecured REST service in Spring Boot Consuming REST service is very simple and less ad-hoc than […]

The post How to consume REST based web service in Spring BOOT appeared first on Little Big Extra.

]]>
Share this article on

How to consume REST based web service in Spring BOOT

Introduction

In my last tutorial I wrote about Consuming a secure SOAP based web service in Spring Boot application, In this tutorial, I will talk about consuming a simple unsecured REST service in Spring Boot
Consuming REST service is very simple and less ad-hoc than SOAP service

Create a REST Template Bean

RestTemplate is spring’s central class for synchronous client side HTTP access.It enforces REST principles and simplifies communication by handlings HTTP connections leaving application code to provide URLs and extract results.
In our code, we will create a bean where we will instantiate a new RestTemplate

@Bean
public RestTemplate rest() {
return new RestTemplate();
}

 

Now we have rest template instance we can use the RestTemplate methods to call web service

Consuming a service by HTTP GET method

You can use Rest Template getForObject or getForEntity methods to make an HTTP GET call. Both of these operations need a URL and the ResponseObject class.
A simple example would be like below.

@GetMapping("/availableOperations")
String getAvailableOperations() {
return restTemplate.getForObject(allAvailableOperations, String.class);
}

 

Consuming a service by HTTP POST method

Consuming a service by POST means that we will be sending some information over HTTP to the requested service and that service based on will request will process things at its end like updating a DB, recording a transaction or something similar and will give us the result back.

In Post also we can use Response Template postForObject and postForEntity Method to send a request

Using postForObject

In below example, we are using an HTTP GET @GetMapping(“/Availability”) method which can be directly called by a  browser using a URL like http://localhost:8080/Availability. In this method, we will call the postForObject method and pass the endpoint URL of the service, the request object it needs and the Response type we expect.

@GetMapping("/availability")
String getURLAvailability() {
return restTemplate.postForObject(url, requestObject(), String.class);
}

 

Using postForEntity

Method post for Entity can be used exactly as shown above, however, the return type is ResponseEntity which represents entire HTTP Response, it has HTTP response like 200,404 etc and response body.

In the below method we have to use a REST CLIENT ( like Chrome plugins Postman or AdvancedRestClient) and directly post the JSON request.

@RequestBody
will automatically map the JSON object to Request object, there is no need to map any elements or create a new request object.

@PostMapping("/availability")
public String postlogdingAvailability(@RequestBody Availability availabilityRequest) {

ResponseEntity response = restTemplate.postForEntity(url, availabilityRequest,
String.class);
return response.getBody();
}

Here is how the complete code looks like

@RestController
@RequestMapping("/")
public class ServiceController {

	@Autowired
	RestTemplate restTemplate;

	
	@Value("${operations.restURL}")
	String serviceURL;


	//Consuming a service by GET method
	@GetMapping("/availableOperations")
	String getAvailableOperations() {
		return restTemplate.getForObject(serviceURL, String.class);
	}

	/**
	 Consuming a service by postForObject method, this method is exposed as a get operation if user doesn't
	 post a request object we will create a new request and post it to the URL/service endpoint
	 */
	@GetMapping("/availability")
	String getAvailability() {
		return restTemplate.postForObject(serviceURL, createAvailabilityRequest(), String.class);
	}

	/**
	 Consuming a service by postForEntity method, this method is exposed as a post operation if user 
	 post a request object(JSON) it will be automatically mapped to Request parameter.
	 */
	@PostMapping("/availability")
	public String postAvailability(@RequestBody Availability availabilityRequest) {
		
		ResponseEntity<String> response = restTemplate.postForEntity(serviceURL, availabilityRequest,
				String.class);
		return response.getBody();
	}

	 

	private Object createAvailabilityRequest() {
		AddOnAvailability addOnAvailability = new AddOnAvailability();
		addOnAvailability.setCheckInDate("09/14/2023");
		addOnAvailability.setCheckOutDate("09/16/2023");
		addOnAvailability.setItemCode("");
		addOnAvailability.setAddOnCategory("10");
		return addOnAvailability;
	}

	 
	@Bean
	public RestTemplate rest() {
		return new RestTemplate();
	}

}

Add the URL in application.yml YAML/properties file

operations:
         serviceURL: https://localhost:8080/addonavailability # This is the rest service end point which needs to be consumed.

 

Maven Dependencies

Following dependencies were enough for above example to work

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

 

 

 

The post How to consume REST based web service in Spring BOOT appeared first on Little Big Extra.

]]>
http://www.littlebigextra.com/consume-rest-based-web-service-spring-boot/feed/ 2
How to consume a secure SOAP Web service in Spring Boot Application http://www.littlebigextra.com/consume-secure-soap-web-service-spring-boot-application/ http://www.littlebigextra.com/consume-secure-soap-web-service-spring-boot-application/#comments Mon, 24 Apr 2023 16:55:04 +0000 http://littlebigextra.com/?p=887 How to consume a secure SOAP Web service by adding WS-SECURITY SOAP header in Spring Boot Application Introduction Consuming a SOAP based web service is one of the common use cases a developer will come across. There are different implementations like JAX-WS, Axis1/2 and CXF which helps us in calling the web services easily. While […]

The post How to consume a secure SOAP Web service in Spring Boot Application appeared first on Little Big Extra.

]]>
Share this article on

How to consume a secure SOAP Web service by adding WS-SECURITY SOAP header in Spring Boot Application

Introduction

Consuming a SOAP based web service is one of the common use cases a developer will come across. There are different implementations like JAX-WS, Axis1/2 and CXF which helps us in calling the web services easily.
While the JAX-WS is the basic implementation built into JDK library for any complex stuff like WS-Security etc we can use Axis or CXF. Apache CXF is JAX-Ws compliant and supports exposing REST as well as SOAP.
For below tutorial, I am going to use CXF implementation

To consume a secure web service we need to follow things in nutshell

  • Generate Java Classes from WSDL using Maven plugin
  • Add UserName Password to WS-Header
  • Calling the Web Service

Adding Maven dependency

To make a call to a secure web service we need to download the associated CXF jars which will be used later.

<dependencies>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-frontend-jaxws</artifactId>
			<version>${cxf.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-ws-policy</artifactId>
			<version>${cxf.version}</version>
		</dependency>

		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-tools-common</artifactId>
			<version>${cxf.version}</version>
		</dependency>

		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-ws-security</artifactId>
			<version>${cxf.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-transports-http</artifactId>
			<version>${cxf.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

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

Generate Java Classes

Apache CXF has CXF-code gen-plugin which can be used to generate Java Classes from WSDL.It can be configured in different ways I have configured it below to generate all the classes in src/main/generated folder under the package com.example.generated

    We need to do following

  • Provide the WSDL file location
  • CXF will generate classes in the specified directory, In our case I have specified it to src/main/generated
  • The generated artifacts can be put in a package by using the <extraargs> parameter.

Here is how the plugin looks like

<plugin>
				<groupId>org.apache.cxf</groupId>
				<artifactId>cxf-codegen-plugin</artifactId>
				<version>${cxf.version}</version>
				<executions>
					<execution>
						<id>generate-sources</id>
						<phase>generate-sources</phase>
						<configuration>
							<additionalJvmArgs>
								-Djavax.xml.accessExternalDTD=all
								-Djavax.xml.accessExternalSchema=all
							</additionalJvmArgs>
							<sourceRoot>${basedir}/src/main/generated</sourceRoot>
							<wsdlOptions>
								<wsdlOption>
									<extraargs>
										<extraarg>-verbose</extraarg>
										<extraarg>-p</extraarg>
										<extraarg>com.example.generated</extraarg>
										<extraarg>-exsh</extraarg>
										<extraarg>true</extraarg>
									</extraargs>
									<wsdl>${basedir}/src/main/resources/wsdl/MyWSDL.wsdl</wsdl>
								</wsdlOption>
							</wsdlOptions>
						</configuration>
						<goals>
							<goal>wsdl2java</goal>
						</goals>
					</execution>
				</executions>
			</plugin>

Adding Source folder

Since in previous step the artifacts were generated under src/main/generated folder we need to make the generated folder as a source folder so all classes will be available and code can be compiled.

    1. In eclipse, click on your project -> Properties -> Java Build Path and add the src/main/generated as a source folder
  • Adding Source Code
    1. Also, we need to make sure that maven also picks this folder while assembling the code and creating executable file, we can use build-helper-maven-plugin as shown below

<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>build-helper-maven-plugin</artifactId>
				<version>3.0.0</version>
				<executions>
					<execution>
						<id>add-source</id>
						<phase>generate-sources</phase>
						<goals>
							<goal>add-source</goal>
						</goals>
						<configuration>
							<sources>
								<source>${basedir}/src/main/generated</source>
							</sources>
						</configuration>
					</execution>
				</executions>
			</plugin>

 

The complete POM

POM should have this plugin to be an executable spring boot jar.

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

 

Here is how the complete POM looks like, By running mvn generate-sources, CXF will generate artifacts in the defined folder in our case (src/main/generated)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>



	<artifactId>sample-api</artifactId>
	<groupId>com.example</groupId>
	<name>MY API</name>
	<description>Example API </description>
	<version>0.0.1-SNAPSHOT</version>


	<properties>
		<main.basedir>${basedir}/../..</main.basedir>
		<maven.compiler.source>1.8</maven.compiler.source>
		<maven.compiler.target>1.8</maven.compiler.target>
		<cxf.version>3.1.10</cxf.version>
	</properties>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.4.3.RELEASE</version>

	</parent>

	<dependencies>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-frontend-jaxws</artifactId>
			<version>${cxf.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-ws-policy</artifactId>
			<version>${cxf.version}</version>
		</dependency>

		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-tools-common</artifactId>
			<version>${cxf.version}</version>
		</dependency>

		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-ws-security</artifactId>
			<version>${cxf.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-transports-http</artifactId>
			<version>${cxf.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

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

	<build>
		<plugins>

			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
			<plugin>
				<groupId>org.apache.cxf</groupId>
				<artifactId>cxf-codegen-plugin</artifactId>
				<version>${cxf.version}</version>
				<executions>
					<execution>
						<id>generate-sources</id>
						<phase>generate-sources</phase>
						<configuration>
							<additionalJvmArgs>
								-Djavax.xml.accessExternalDTD=all
								-Djavax.xml.accessExternalSchema=all
							</additionalJvmArgs>
							<sourceRoot>${basedir}/src/main/generated</sourceRoot>
							<wsdlOptions>
								<wsdlOption>
									<extraargs>
										<extraarg>-verbose</extraarg>
										<extraarg>-p</extraarg>
										<extraarg>com.example.generated</extraarg>
										<extraarg>-exsh</extraarg>
										<extraarg>true</extraarg>
									</extraargs>
									<wsdl>${basedir}/src/main/resources/wsdl/MyWSDL.wsdl</wsdl>
								</wsdlOption>
							</wsdlOptions>
						</configuration>
						<goals>
							<goal>wsdl2java</goal>
						</goals>
					</execution>
				</executions>
			</plugin>

			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>build-helper-maven-plugin</artifactId>
				<version>3.0.0</version>
				<executions>
					<execution>
						<id>add-source</id>
						<phase>generate-sources</phase>
						<goals>
							<goal>add-source</goal>
						</goals>
						<configuration>
							<sources>
								<source>${basedir}/src/main/generated</source>
							</sources>
						</configuration>
					</execution>
				</executions>
			</plugin>

		</plugins>
	</build>
</project>

Identifying the Service Interface and Port Class

From our generated classes we need to find the Service Class and right operation which we need to call. The code will generate classes like ObjectFactory which contains various namespaces along with a ServiceInterface which contains the service operations
Open the interface and look for methods which have annotation

@WebMethod(action = "serviceOperation")
these are the various service operations which have been exposed by WSDL

@WebService(targetNamespace = "http://crmCommon/content/outboundMessage/", name = "MYServicePortType")
@XmlSeeAlso({ObjectFactory.class})
public interface MyService {

    @WebMethod(action = "serviceOperation")
    @RequestWrapper(localName = "serviceOperation", targetNamespace = "http://crmCommon/content/outboundMessage/types/", className = "com.gen.lookup.ProcessType")
    @ResponseWrapper(localName = "serviceOperationResponse", targetNamespace = "http://crmCommon/content/outboundMessage/types/", className = "com.gen.lookup.ProcessResponseType")
    public void serviceOperation(

Another class is also known as Port which implements the service endpoint interface defined by Service will also be in generated folder. We Will use these classes to make a call to web service.

@WebServiceClient(name = "Source_WEB_Contact_Contact_ENDPOINTPortType", 
                  wsdlLocation = "file://src/main/resources/wsdl/LookUp.wsdl",
                  targetNamespace = "http:///crmCommon/content/outboundMessage/") 
public class MyServicePort extends Service {

    public final static URL WSDL_LOCATION;

    public final static QName SERVICE = new QName("http:///crmCommon/content/outboundMessage/", "Source_WEB_Contact_Contact_ENDPOINTPortType");
    public final static QName SourceWEBContactContactENDPOINTPortTypePt = new QName("http:///crmCommon/content/outboundMessage/", "Source_WEB_Contact_Contact_ENDPOINTPortType_pt");
    static {

Calling the web service

Create a new instance of Service class

MyServicePort service = new MyServicePort();

The method 

getPort
 returns a proxy. The parameter in below method specifies the service endpoint interface that is supported by the returned proxy.

MyService port = service.getPort(MyService.class);

Use the BindingProvider interface and type cast port to be of type BindingProvider

BindingProvider provider = (BindingProvider) port;

Adding UserName Password

Use the properties ws-security.username and ws-security.password to define the UserName and Password

provider.getRequestContext().put("ws-security.username", "myusername");
provider.getRequestContext().put("ws-security.password", "mypassword");

Override the defaultWSDL URL

provider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
				"https://mycustomerURL/replacethis");

Adding TimeStamp

If the security policy is defined in the WSDL requires a timestamp to avoid replay attacks CXF will automatically add the timestamp to the request.

Call the Web Service

Invoke the port’s method(service operation)

port.serviceOperation(request);

That’s all, You can add below Logging In and Logging Out interceptor to print request response in code

org.apache.cxf.endpoint.Client client = org.apache.cxf.frontend.ClientProxy.getClient(port);
		org.apache.cxf.endpoint.Endpoint cxfEndpoint = client.getEndpoint();
	
		cxfEndpoint.getOutInterceptors().add(new LoggingInInterceptor());
		cxfEndpoint.getOutInterceptors().add(new LoggingOutInterceptor());

The post How to consume a secure SOAP Web service in Spring Boot Application appeared first on Little Big Extra.

]]>
http://www.littlebigextra.com/consume-secure-soap-web-service-spring-boot-application/feed/ 3
How to Add Bootstrap Css and JQuery To Spring Boot MVC Application http://www.littlebigextra.com/add-bootstrap-css-jquery-to-springboot-mvc/ http://www.littlebigextra.com/add-bootstrap-css-jquery-to-springboot-mvc/#respond Thu, 06 Apr 2023 15:24:31 +0000 http://littlebigextra.com/?p=854 How to add Bootstrap, Font-Awesome and Jquery to spring Boot Project Introduction Twitter Bootstrap is one of the most popular front-end frameworks for responsive web design and development. Font Awesome provides us with scalable vector icons that can be customised. Needless to say, anything about Jquery, since it is the number 1 Javascript framework and […]

The post How to Add Bootstrap Css and JQuery To Spring Boot MVC Application appeared first on Little Big Extra.

]]>
Share this article on

How to add Bootstrap, Font-Awesome and Jquery to spring Boot Project

Introduction

Twitter Bootstrap is one of the most popular front-end frameworks for responsive web design and development.

Font Awesome provides us with scalable vector icons that can be customised. Needless to say, anything about Jquery, since it is the number 1 Javascript framework and has been so from last 10 years.

It is Imperative that for your Spring Boot MVC based application you will require either of the above technologies to make your web pages look better.

Add Maven Dependencies

We need to add dependency for

  • Jquery
  • Bootstrap
  • FontAwesome

Apart from above, we need to add a dependency for web jars locator which lets us locate the CSS and JS files without providing the exact version of files.

<dependency>
			<groupId>org.webjars</groupId>
			<artifactId>jquery</artifactId>
			<version>2.1.1</version>
		</dependency>
		<dependency>
			<groupId>org.webjars</groupId>
			<artifactId>bootstrap</artifactId>
			<version>3.2.0</version>
		</dependency>
		<dependency>
			<groupId>org.webjars</groupId>
			<artifactId>webjars-locator</artifactId>
		</dependency>
		<dependency>
			<groupId>org.webjars</groupId>
			<artifactId>font-awesome</artifactId>
			<version>4.7.0</version>
		</dependency>

 

Annotations

Make sure you have either of the annotations in your Spring Boot

@SpringBootApplication

or
@EnableWebMvc

@SpringBootApplication is equivalent of using all three @Configuration, @EnableWebMvc and @ComponentScan
@SpringBootApplication = @Configuration + @EnableWebMvc+@ComponentScan

Add the reference in HTML pages

In the HTML page, you need to provide link to CSS and javascript src files location. Add the below head section in your *.html file
Note that the path doesn’t contain any specific version of CSS file or js files, thanks to web jars-locator dependency. That would mean that even if you change the version in your pom.xml there is no need to change any reference in HTML

<head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <title>Login</title>
    <meta name="description" content=""/>
    <meta name="viewport" content="width=device-width"/>
    <base href="/"/>
    <link rel="stylesheet" type="text/css" href="/webjars/bootstrap/css/bootstrap.min.css"/>
    <script type="text/javascript" src="/webjars/jquery/jquery.min.js"></script>
    <script type="text/javascript" src="/webjars/bootstrap/js/bootstrap.min.js"></script>
    <link rel="stylesheet" href="/webjars/font-awesome/css/font-awesome.min.css"></link>
</head>

Add the HTML

You can use any of the above CSS classes from bootstrap and font awesome or js files from Jquery with your HTML pages.

<div class="container">
		
		<a href="/login" class="btn btn-primary"><span class="fa fa-user"></span> SignIn</a>
        <a href="/logout" class="btn btn-danger">Logout <span class="fa fa-sign-out"></span> </a>
         <a href="/facebook" class="btn btn-primary">Facebook <span class="fa fa-facebook"></span> </a>       
        <a href="/google" class="btn btn-danger"> Google <span class="fa fa-google-plus"></span> </a> 
        <a href="/linkedin" class="btn btn-primary">LinkedIn <span class="fa fa-linkedin"></span> </a> 
 </div>

 

Run the application

For above code, I got the following output. Bootstrap button classes and icons from font-awesome have been applied to the buttons.
Adding Bootstrap ,Font Awesome and Jquery to SPring Boot

Follow this Video for reference

The post How to Add Bootstrap Css and JQuery To Spring Boot MVC Application appeared first on Little Big Extra.

]]>
http://www.littlebigextra.com/add-bootstrap-css-jquery-to-springboot-mvc/feed/ 0
How to access LinkedIn data using spring-social http://www.littlebigextra.com/spring-social-linkedin-example/ http://www.littlebigextra.com/spring-social-linkedin-example/#respond Wed, 05 Apr 2023 11:31:58 +0000 http://littlebigextra.com/?p=837 How to access LinkedIn data using spring-social and spring boot Introduction Spring Social provides the capability which enables our application to interact with LinkedIn Rest API and get user data. Considering how popular social logins have become recently, it is a nice feature to have on your website. Getting started I would suggest you to […]

The post How to access LinkedIn data using spring-social appeared first on Little Big Extra.

]]>
Share this article on

How to access LinkedIn data using spring-social and spring boot

Introduction

Spring Social provides the capability which enables our application to interact with LinkedIn Rest API and get user data. Considering how popular social logins have become recently, it is a nice feature to have on your website.

Getting started

I would suggest you to first clone the as it does have required page structure and dependencies

Add Maven Dependencies

Add the spring-social-google dependency

org.springframework.social
			spring-social-linkedin
			1.0.0.RELEASE

Update the application.properties

Now update the application.properties with your secret and client key

spring.social.linkedin.app-id=771mrzk94hye1w
spring.social.linkedin.app-secret=iIJFgBf9lCb18zYe

Add the HTML for LinkedIn

Under src/main/resources/templates/connect you should have facebookConnect.html and facebookConnected.html, if you have cloned/downloaded the spring tutorial properly.
Again replace facebook with linkedin in HTML and save them as linkedinConnected.html and linkedinConnect.html or copy them as shown below. Make sure the scope is properly defined in your request.

<input type="hidden" name="scope" value="r_basicprofile,r_emailaddress" />

linkedinConnect.html

<html>
	<head>
		<title>Hello LinkedIn</title>
	</head>
	<body>
		<h3>Connect to Linkedin</h3>
		
		<form action="/connect/linkedin" method="POST">
			<input type="hidden" name="scope" value="r_basicprofile,r_emailaddress" />
			<div class="formInfo">
				<p>You aren't connected to LinkedIn yet. Click the button to connect this application with your  account.</p>
			</div>
			<p><button type="submit">Connect to LinkedIn</button></p>
		</form>
	</body>
</html>

linkedinConnected.html

<html>
	<head>
		<title>Hello Facebook</title>
	</head>
	<body>
		<h3>Connected to LinkedIn</h3>
		
		<p>
			You are now connected to your LinkedIn account.
			Click <a href="/linkedin">here</a> to see some entries from your LinkedIn feed.
		</p>		
	</body>
</html>

Add a @Controller for LinkedIn

We need to add a rest controller so it can handle LinkedIn authorization requests

@Controller
@RequestMapping("/linkedin")
public class LinkedInController {

    private LinkedIn linkedIn;
    private ConnectionRepository connectionRepository;

    public LinkedInController(LinkedIn linkedIn, ConnectionRepository connectionRepository) {
        this.linkedIn = linkedIn;
   
        this.connectionRepository = connectionRepository;
    }
    

    @GetMapping
    public String helloFacebook(Model model) {
        if (connectionRepository.findPrimaryConnection(LinkedIn.class) == null) {
            return "redirect:/connect/linkedin";
            
        }
        ProfileOperations user = linkedIn.profileOperations();
        System.out.println(user);
        model.addAttribute("linkedInProfile",linkedIn.profileOperations().getUserProfileFull());
        
    
        
        return "linkedin";
    } 
}

@RequestMapping(“/linkedin”), your application should run on localhost:port/linkedin to test this example

Add HTML to show user details

In src/main/resources add a file called “linkedin.html” at same level as “hello.html”

<html>
	<head>
		<title>Hello Facebook</title>
	</head>
	<body>
		<h3>Hello, <span th:text="${linkedInProfile.firstName}"></span><span th:text="${linkedInProfile.lastName}"></span></h3>
		
		<h4><span th:text="${linkedInProfile.emailAddress}"></span></h4>
		<h4><span th:text="${linkedInProfile.id}"></span></h4>
		<h4><span th:text="${linkedInProfile.location.country}"></span></h4>
		
	</body>
</html>

That’s all

Run the application on localhost: port/linkedin and you should be authenticated. Drop comments if you face any problem

Please note that this example works only for one user if you want to make it work for multiple users go through below link

If you want to change the default page flow (linkedinconnect.tml to connect/linkedinConnected.html),please follow below link

The post How to access LinkedIn data using spring-social appeared first on Little Big Extra.

]]>
http://www.littlebigextra.com/spring-social-linkedin-example/feed/ 0
How to access google data using spring-social and spring boot http://www.littlebigextra.com/access-google-data-using-spring-social/ http://www.littlebigextra.com/access-google-data-using-spring-social/#respond Tue, 04 Apr 2023 16:54:57 +0000 http://littlebigextra.com/?p=797 How to access google data using spring-social Introduction Spring social do have a spring-social-google project but it doesn’t have autoconfiguration for Google. So google authorization doesn’t work with spring boot autoconfigure straight away. I had created a pull request and merged the code to spring repository but got the following reply Thanks for the PR. […]

The post How to access google data using spring-social and spring boot appeared first on Little Big Extra.

]]>
Share this article on

How to access google data using spring-social

Introduction

Spring social do have a spring-social-google project but it doesn’t have autoconfiguration for Google. So google authorization doesn’t work with spring boot autoconfigure straight away. I had created a pull request and merged the code to spring repository but got the following reply
Thanks for the PR. We’ve already considered this in #2548 where we decided that it isn’t something that we want to include in Spring Boot. That’s still the case so I’m going to close this. Thanks anyway.

So it doesn’t look like sooner or later they are going to add autoconfigure functionality to Spring-Social-Google

What needs to be done to enable spring social autoconfigure

    To enable autoconfigure of spring-social-google we need to

  • Add Maven dependency
  • Add a GoogleAutoConfiguration
  • Add GoogleProperties
  • Modify HTML pages

Getting started

I would suggest you to first clone the as it does have required page structure and dependencies

Add Maven Dependencies

Add the spring-social-google dependency

<dependency>
			<groupId>org.springframework.social</groupId>
			<artifactId>spring-social-google</artifactId>
			<version>1.0.0.RELEASE</version>
		</dependency>

Add a GoogleAutoConfiguration Class

Do Ctrl+Shift+T  in your IDE(eclipse) and look for FacebookAutoConfiguration class you should be able to find it either in org.springframework.boot.autoconfigure.social package in spring-autoconfigure.jar
Copy this File and replace Facebook with Google. Alternatively, copy the below class and put in some package, make sure it is available in classpath(src/main/java or inside another source folder)

@Configuration
@ConditionalOnClass({ SocialConfigurerAdapter.class, GoogleConnectionFactory.class })
@ConditionalOnProperty(prefix = "spring.social.google", name = "app-id")
@AutoConfigureBefore(SocialWebAutoConfiguration.class)
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
public class GoogleAutoConfiguration {

	@Configuration
	@EnableSocial
	@EnableConfigurationProperties(GoogleProperties.class)
	@ConditionalOnWebApplication
	protected static class GoogleConfigurerAdapter extends SocialAutoConfigurerAdapter {

		private final GoogleProperties properties;

		protected GoogleConfigurerAdapter(GoogleProperties properties) {
			this.properties = properties;
		}

		@Bean
		@ConditionalOnMissingBean(Google.class)
		@Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
		public Google google(ConnectionRepository repository) {
			Connection connection = repository.findPrimaryConnection(Google.class);
			return connection != null ? connection.getApi() : null;
		}

		@Bean(name = { "connect/googleConnect", "connect/googleConnected" })
		@ConditionalOnProperty(prefix = "spring.social", name = "auto-connection-views")
		public GenericConnectionStatusView googleConnectView() {
			return new GenericConnectionStatusView("google", "Google");
		}

		@Override
		protected ConnectionFactory<?> createConnectionFactory() {
			return new GoogleConnectionFactory(this.properties.getAppId(), this.properties.getAppSecret());
		}

	}

}

Add GoogleProperties

In the same package add the below class

import org.springframework.boot.autoconfigure.social.SocialProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "spring.social.google")

public class GoogleProperties extends SocialProperties{

	
}

Update the application.properties

Now update the application.properties with your secret and client key

spring.social.google.appId=12894100090-tqso3lih5o42isneort886la2pesafmp.apps.googleusercontent.com
spring.social.google.appSecret=9xfU16efvxQ-BTMsXT9wO

Add the HTML for Google

Under src/main/resources/templates/connect you should have facebookConnect.html and facebookConnected.html, if you have cloned the project properly.Again replace facebook with google in HTML and save them as googleConnected.html and googleConnect.html or copy them as shown below.

googleConnect.html

<html>
	<head>
		<title>Hello Google</title>
	</head>
	<body>
		<h3>Connect to Google</h3>
		
		<form action="/connect/google" method="POST">
			<input type="hidden" name="scope" value="profile" />
			<div class="formInfo">
				<p>You aren't connected to Google yet. Click the button to connect this application with your  account.</p>
			</div>
			<p><button type="submit">Connect to Google</button></p>
		</form>
	</body>
</html>

googleConnected.html

<html>
	<head>
		<title>Hello Google</title>
	</head>
	<body>
		<h3>Connected to Google</h3>
		
		<p>
			You are now connected to your Google account.
			Click <a href="/google">here</a> to see some entries.
		</p>		
	</body>
</html>

Add a @Controller for Google

We need to add a rest controller so it can handle google authorization requests

@Controller
@RequestMapping("/google")
public class GoogleController {

    private Google google;
    private ConnectionRepository connectionRepository;

    public GoogleController(Google google, ConnectionRepository connectionRepository) {
        this.google = google;
        this.connectionRepository = connectionRepository;
    }
    
   

    @GetMapping
    public String helloFacebook(Model model) {
        if (connectionRepository.findPrimaryConnection(Google.class) == null) {
            return "redirect:/connect/google";
        }
        Person user = google.plusOperations().getGoogleProfile();
 
        System.out.println(google.isAuthorized());
        
        System.out.println(": "+user.getGivenName() +" : "+ user.getEmailAddresses() +" : "+ user.getFamilyName());
        model.addAttribute("googleProfile", user);
        return "google";
    }

    
}

@RequestMapping(“/google”), your application should run on localhost:port/google to test this example

Add HTML to show user details

In src/main/resources add a file called “google.html” at same level as “hello.html”

<html>
	<head>
		<title>Hello Google</title>
	</head>
	<body>
		<h3>Hello, <span th:text="${googleProfile.givenName}"></span><span th:text="${googleProfile.familyName}"></span></h3>
		
		
		<h4><span th:text="${googleProfile.id}"></span></h4>
		
		<div th:each="post:${googleProfile.emailAddresses}">
			Email : <b th:text="${post}"></b> 
			
			<hr/>
		</div>
	</body>
</html>

That’s all

Run the application on localhost: port/google and you should be authenticated. Drop comments if you face any problem

Please note that this example works only for one user, if you want to make it work for multiple users go through below link

Happy Coding, hope it helps.

The post How to access google data using spring-social and spring boot appeared first on Little Big Extra.

]]>
http://www.littlebigextra.com/access-google-data-using-spring-social/feed/ 0