How to generate bearer token when clicking on the link in email - java

I want to generate bearer token when someone clicked on the email link, this token contains the identity of the person who clicked on the email link and if person forwarded the email to other person then bearer token should contain identity of forwarded person when he click on the email link(purpose of including identity here is validation of person at server side).
Email link contains service call when clicked it will call service and validate bearer token.
Approve
Appreciate any comments here

I'm generating token after the user verifies OTP. In your case, you don't need to verify anything.
API Method
public async Task<IActionResult> LoginFunction(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "Account/Login")] HttpRequest req, ILogger log)
{
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
var accountDto = JsonConvert.DeserializeObject<AccountDto>(requestBody);
log.LogInformation($"ValidateOTP for phoneNumber {accountDto.PhoneNumber}");
var isUserValid = await this.accountService.ValidateOTP(accountDto.PhoneNumber, accountDto.OTP);
if (isUserValid)
{
return (ActionResult)new OkObjectResult(BuildToken(accountDto));
}
return (ActionResult)new NotFoundObjectResult("Invalid OTP");
}
private UserToken BuildToken(AccountDto accountDto)
{
var claims = new[]
{
new Claim(ClaimTypes.MobilePhone, accountDto.PhoneNumber)
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("LKM3LKM344NKSFN4KJ345N43KJN4KJFNK")); //read from config
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
// Expiration time
var expiration = DateTime.UtcNow.AddYears(1);
JwtSecurityToken token = new JwtSecurityToken(
issuer: AppConstraint.TokenIssuer,
audience: AppConstraint.Audience,
claims: claims,
expires: expiration,
signingCredentials: creds);
return new UserToken()
{
Token = new JwtSecurityTokenHandler().WriteToken(token),
Expiration = expiration
};
}
Once you will get token you can store that token to the user's browser and send with each request.
Custom Authorize Attribute Using MrAdvice Aspect
public class AuthorizedAttribute : Attribute, IMethodAsyncAdvice
{
public async Task Advise(MethodAsyncAdviceContext context)
{
try
{
try
{
HttpRequest request = (HttpRequest)context.Arguments[0];
var tokenString = request.Headers[AppConstraint.Authorization].ToString().Split(' ')[1];
JwtSecurityToken token = new JwtSecurityTokenHandler().ReadJwtToken(tokenString);
if (token.ValidTo <= DateTime.Now)
{
throw new SecurityTokenExpiredException("Token has expired");
}
var claimPrincipal = GetIdentityFromToken(tokenString);
request.HttpContext.User = claimPrincipal;
}
catch
{
context.ReturnValue = Task.FromResult<IActionResult>((ActionResult)new UnauthorizedResult());
return;
}
await context.ProceedAsync(); // this calls the original method
}
catch
{
throw;
}
}
private ClaimsPrincipal GetIdentityFromToken(string token)
{
var tokenParams = new TokenValidationParameters()
{
RequireSignedTokens = true,
ValidAudience = AppConstraint.Audience,
ValidateAudience = true,
ValidIssuer = AppConstraint.TokenIssuer,
ValidateIssuer = true,
ValidateIssuerSigningKey = true,
ValidateLifetime = true,
IssuerSigningKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes("LKM3LKM344NKSFN4KJ345N43KJN4KJFNK"))
};
var handler = new JwtSecurityTokenHandler();
var result = handler.ValidateToken(token, tokenParams, out _);
return result;
}
}
Hope this will help to generate and verify your own token.

Related

Refresh JWT expired token with Angular 11 interceptor from Spring Boot back end

I am working on a spring boot + angular project in which a user logs in from Angular front end to the authentication api on Spring Boot, which returns a JWT token. I also set up an interceptor on Angular that appends the Authorization header with the JWT token for all requests.
I am looking for a way to intercept angualar requests so that when spring boot throws a 401 error once the JWT token is expired, the Angular front end will try to contact the new refreshtoken endpoint with the expired JWT and a new "isRefreshToken" header set to true to receive a new JWT.
This is my current AuthService
#Injectable({
providedIn: 'root',
})
export class AuthService {
constructor(private http: HttpClient) {}
login(username: string, password: string) {
return this.http
.post<iUser>('http://localhost:8080/authenticate', { username, password }).pipe(
tap(res => this.setSession(res)),
shareReplay()
)
}
refreshToken(){
return this.http.post<iUser>('http://localhost:8080/refreshtoken', {responseType: 'text' as 'json'}).pipe(
tap(res => this.setSession(res)),
shareReplay()
)
}
private setSession(authResult) {
let tokenInfo = this.getDecodedAccessToken(authResult.token);
const expiresAt = moment(tokenInfo.exp);
localStorage.setItem('id_token', authResult.token);
localStorage.setItem('expires_at', JSON.stringify(expiresAt.valueOf()));
localStorage.setItem('userId', tokenInfo.userId);
}
logout() {
localStorage.removeItem('id_token');
localStorage.removeItem('expires_at');
localStorage.removeItem('userId');
}
public isLoggedIn() {
return moment().isBefore(this.getExpiration());
}
isLoggedOut() {
return !this.isLoggedIn();
}
getExpiration() {
const expiration = localStorage.getItem('expires_at');
const expiresAt = JSON.parse(expiration);
return moment.unix(expiresAt);
}
getDecodedAccessToken(token: string): any {
try{
return jwt_decode(token);
}
catch(Error){
return null;
}
}
}
While this is the interceptor I am using:
#Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private router: Router, private authService: AuthService){}
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
let url = req.url.includes('localhost');
const idToken = localStorage.getItem('id_token');
if (idToken && url) {
const cloned = req.clone({
headers: req.headers.set('Authorization', 'Bearer ' + idToken),
});
console.log(cloned);
return next.handle(cloned);
} else {
return next.handle(req);
}
}
}
I can suggest to you another way of doing this which I used recently to log out a user when the token expires. Let me share my approach first:
loginUser(email: string, password: string) {
const authData: AuthData = { email: email, password: password };
this.http.post<{ token: string, expiresIn: number }>('http://localhost:3000/api/users/login', authData).subscribe( response => {
const token = response.token;
this.token = token;
if(token) {
const expiresInDuration = response.expiresIn;
this.tokenTimer = setTimeout(() => {
this.logout();
}, expiresInDuration*1000);
this.isAuthenticated = true;
this.authStatusListener.next(true);
const now = new Date();
const expirationDate = new Date(now.getTime() + (expiresInDuration * 1000));
this.saveAuthData(token, expirationDate);
this.router.navigate(['']);
}
});
}
logout() {
this.token = null;
this.isAuthenticated = false;
this.authStatusListener.next(false);
clearTimeout(this.tokenTimer);
this.clearAuthData();
this.router.navigate(['']);
}
private saveAuthData(token: string, expirationDate: Date) {
localStorage.setItem('token', token);
localStorage.setItem('expirationDate', expirationDate.toISOString());
}
So what I have done here is I have received a expireIn value which is in seconds when the token will expire. Then I have set a timeout callback method which will be called when that time is reached. Here I've logged out in your case you can call the API for the refresh token & make desired changes as per your requirement. So coming back to the point, I have set the expiration date & time with respect to the current date-time of login with expiresIn duration. Also added a authStatusListener Subject which will listen to the state of the authentication till it expires.
Nothing extra to do in Interceptor/Guard for token expiration
For controlling the logout button in header just do like this:
userIsAuthenticated = false;
private authListenerSubs: Subscription;
constructor(private authService: AuthService) { }
onLogout() {
this.authService.logout();
}
ngOnInit() {
this.authListenerSubs = this.authService.getAuthStatusListener().subscribe(isAuthenticated => {
this.userIsAuthenticated = isAuthenticated;
});
}
ngOnDestroy() {
this.authListenerSubs.unsubscribe();
}
Use userIsAuthenticated in ngIf in the HTML.
For a real scenario you can take help of this github repo.

Get user profile from GoogleIdToken

I'm trying to do this:
https://developers.google.com/identity/sign-in/web/backend-auth#calling-the-tokeninfo-endpoint
I copy pasted the Java code from the example, with my CLIENT_ID, but I can't get any more information than user id, email and email verified. idTokenString verifies OK. Have anyone else got this to work?
I asked for these in OAuth 2.0 Playground:
https://www.googleapis.com/auth/plus.login
https://www.googleapis.com/auth/plus.me
https://www.googleapis.com/auth/userinfo.email
https://www.googleapis.com/auth/userinfo.profile
https://www.googleapis.com/auth/plus.moments.write
https://www.googleapis.com/auth/plus.profile.agerange.read
https://www.googleapis.com/auth/plus.profile.language.read
https://www.googleapis.com/auth/plus.circles.members.read
I guess the user.profile is the one i need only?
This is my code:
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
.setAudience(Arrays.asList(CLIENT_ID))
.setIssuer("accounts.google.com")
.build();
GoogleIdToken idToken = verifier.verify(idTokenString);
System.out.println("SUCCESS!");
System.out.println(idToken);
if (idToken != null) {
GoogleIdToken.Payload payload = idToken.getPayload();
// Print user identifier
String userId = payload.getSubject();
System.out.println("User ID: " + userId);
// Get profile information from payload
String email = payload.getEmail();
boolean emailVerified = payload.getEmailVerified();
String name = (String) payload.get("name");
String pictureUrl = (String) payload.get("picture");
String locale = (String) payload.get("locale");
String familyName = (String) payload.get("family_name");
String givenName = (String) payload.get("given_name");
// Use or store profile information
// ...
System.out.println(email);
System.out.println(emailVerified);
System.out.println(name);
System.out.println(pictureUrl);
System.out.println(locale);
System.out.println(familyName);
System.out.println(givenName);
} else {
System.out.println("Invalid ID token.");
}
} catch (GeneralSecurityException | IOException e) {
System.out.println("ERRRRO! Invalid ID token.");
}
Using: java-api-client 1.20.0
I encountered the same issue today using com.google.api-client:google-api-client:1.22.0
But I was able to solve it.
Problem
When trying to get id token from OAuth2 playground I've noticed that there is this request
POST /oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
The Google library has hard coded TOKEN_SERVER_URL in GoogleOAuthConstants with value https://accounts.google.com/o/oauth2/token
Fix
To fix it I've created following class
public class GoogleAuthorizationCodeTokenV4Request extends GoogleAuthorizationCodeTokenRequest {
public GoogleAuthorizationCodeTokenV4Request(HttpTransport transport, JsonFactory jsonFactory, String clientId, String
clientSecret, String code, String redirectUri) {
super(transport, jsonFactory, "https://www.googleapis.com/oauth2/v4/token", clientId, clientSecret,
code, redirectUri);
}
}
And then just invoke it instead the original GoogleAuthorizationCodeTokenRequest
return new GoogleAuthorizationCodeTokenV4Request(new NetHttpTransport(), JacksonFactory.getDefaultInstance(),
clientId, secret, authToken, callBack)
.execute();
With profile scope all information (picture, names, ...) are in id_token

How to activate a user through email verification

Right now I am sending a confirmation link containing JWT token created for user to recipients mail address. This token is saved in a database column.
The activation link looks like this:
http://localhost:7070/RTH_Sample14/eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvcnRoLmNvbSIsInN1YiI6IlJUSCIsInJvbGUiOiJVU0VSIiwiZXhwIjoxNDU2MjQ1MzM2LCJlbWFpbCI6Imtpcml0aS5rOTk5QGdtYWlsLmNvbSJ9.RJ54PhKcj9GGMq_VefQEMhY0x38wX1t5GgMldHCRmBZsPKoXAYg5vr39aXjHtKmIDsoqmDdzzjsrEIweWEATg3-jGe_PGfxwKZg1zsKiWlpavvKJn92VgffJi1yO54t-H31n2NKjVhAcay34pf3eUNqpPcDCEz9uf_GwSZl1ZTM
When the user clicks on the link, I want to be able to call a restful resource (#Path("/public/emailActivation")) which checks for token in database and change the account-status column from "pending" to "active"
The problem is how would I point the activation-link to rest resource method when clicked?
Is this the right approach to activate/verify user?
Rest Registration Service:
#Path("/public/registrationService")
public class RegistrationService {
public RegistrationService() {
}
#POST
#Path("/register")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response register(UserProfile user) {
String email = user.getEmail();
String token = "";
try {
RegistrationDAO registrationDao = new RegistrationDAO();
int count = registrationDao.insert(user);
if (count > 0) {
System.out.println("Registration successful");
TokenProvider jwtProvider = new TokenProvider();
token = jwtProvider.getToken(email);
Map<String, String> response = new HashMap<>();
response.put("token", token);
SendEmailConfirmation mailActivation = new SendEmailConfirmation();
mailActivation.sendMail(email, "http://localhost:7070/RTH_Sample14/"+token);
return Response.ok(response).build();
}
else {
return Response.status(Response.Status.UNAUTHORIZED).type("text/plain").entity("Registration failed!").build();
}
} catch (Exception e) {
e.printStackTrace();
return Response.status(Response.Status.NOT_FOUND).type("text/plain").entity("Error in Login Service web service class").build();
}
}
}
This method should be called for mail activation when user clicks on link:
#Path("/public/emailActivation")
public class EmailActivation {
#Path("/activate")
public void activateAccount(){
//Check Database for token and account status
}
}

Bonita Web API - 401 Unauthorized Error

I am trying to use Bonita Web API. I My code is below. As you can see I call the loginservice before calling any other API service. It logs in OK 200. But when I make the subsequent call to get the list of processes I get a 401 error. You get a JSESSIONID from the first call and you are suppose to pass it to the subsequent calls to authenticate you.
var baseAddress = new Uri(<base address>);
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
HttpResponseMessage result = client.PostAsync("/bonita/loginservice", new StringContent("login=<username>,password=<password>,redirect=false")).Result;
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage result2 = client.GetAsync("/bonita/API/bpm/process").Result;
result2.EnsureSuccessStatusCode();
}
This works for .Net 2.0 C# but has some interesting things to check.
WebClient wc = new WebClient();
wc.Proxy = WebRequest.GetSystemWebProxy();
//wc.Headers[HttpRequestHeader.AcceptEncoding] = "gzip, deflate";
string strLogin = wc.DownloadString("http://localhost:8080/bonita/loginservice?username=walter.bates&password=bpm&redirect=false");
wc.Headers[HttpRequestHeader.Cookie] = wc.ResponseHeaders[HttpResponseHeader.SetCookie].ToString();
string strCookie = wc.ResponseHeaders[HttpResponseHeader.SetCookie].ToString();
string strProcesses = wc.DownloadString("http://localhost:8080/bonita/API/bpm/process?p=0");
First of all you should know how to determine that the executed operation is successful ( login, getProcesses and whatever) When you try to login you will always get the header (for example "JSESSIONID=50E509D37AC28E2D725CBD45A8112FA7; Path=/bonita; HttpOnly") and OK 200 even if your login attempt in Bonita is unsuccesful.
For the successful login on the previous example
1) You must Pass mandatory form data: username, password and redirect You must also be sure to pass redirect in lower case ."False" will not work, "false" will work. So for .Net suppose you have a property-> Boolean redirect. You must make it lowercase with redirect.ToString().ToLower() cause either way the value will be "False" and you don't want that.
Let's say you try to login only with username and password without passing redirect. the result is that you will get both OK 200 and the header but you will also get a response which is wrong (the response must be empty), so on the next request (i.e getProcesses) you'll get (401) Unauthorized. Guess the results you will have if you pass redirect=False instead of redirect=false. Exactly the same.
2)You must get: strLogin="" // the body of the response must be empty strCookie="JSESSIONID=4F67F134840A2C72DBB968D53772FB22; Path=/bonita; HttpOnly"
For the successful getProcesses on the previous example you pass the header you got from login
wc.Headers[HttpRequestHeader.Cookie] = wc.ResponseHeaders[HttpResponseHeader.SetCookie].ToString();
and then you call the process and get a string in json format for example
"[{\"id\":\"6996906669894804403\",\"icon\":\"\",\"displayDescription\":\"\",\"deploymentDate\":\"2014-11-19 17:57:40.893\",\"description\":\"\",\"activationState\":\"ENABLED\",\"name\":\"Travel request\",\"deployedBy\":\"22\",\"displayName\":\"Travel request\",\"actorinitiatorid\":\"4\",\"last_update_date\":\"2014-11-19 17:57:41.753\",\"configurationState\":\"RESOLVED\",\"version\":\"1.0\"}]"
(or [] which means an empty json)
If the cookie is not passed correctly you will get again 401 error.
Solution for .Net 4.5.1
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace BonitaRestApi
{
class BonitaApi
{
private CookieCollection collection;
string strCookietoPass;
string sessionID;
static void Main(string[] args)
{
BonitaApi obj = new BonitaApi();
Task login = new Task(obj.Login);
login.Start();
login.Wait();
Console.ReadLine();
Task GetProcesses = new Task(obj.GetProcesses);
GetProcesses.Start();
GetProcesses.Wait();
Console.ReadLine();
Task logout = new Task(obj.Logout);
logout.Start();
logout.Wait();
Console.ReadLine();
}
public async void Login()
{
const string url = "http://localhost:8080/bonita/";
var cookies = new CookieContainer();
var handler = new HttpClientHandler();
handler.CookieContainer = cookies;
using (var client = new HttpClient(handler))
{
var uri = new Uri(url);
client.BaseAddress = uri;
//client.DefaultRequestHeaders.Accept.Clear();
//client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("username", "helen.kelly"),
new KeyValuePair<string, string>("password", "bpm"),
new KeyValuePair<string, string>("redirect", "false"),
new KeyValuePair<string, string>("redirectUrl", ""),
});
HttpResponseMessage response = await client.PostAsync("loginservice", content);
if (response.IsSuccessStatusCode)
{
var responseBodyAsText = await response.Content.ReadAsStringAsync();
if (!String.IsNullOrEmpty(responseBodyAsText))
{
Console.WriteLine("Unsuccessful Login.Bonita bundle may not have been started, or the URL is invalid.");
return;
}
collection= cookies.GetCookies(uri);
strCookietoPass = response.Headers.GetValues("Set-Cookie").FirstOrDefault();
sessionID = collection["JSESSIONID"].ToString();
Console.WriteLine(string.Format("Successful Login Retrieved session ID {0}", sessionID));
// Do useful work
}
else
{
Console.WriteLine("Login Error" + (int)response.StatusCode + "," + response.ReasonPhrase);
}
}
}
public async void Logout()
{
const string url = "http://localhost:8080/bonita/";
var cookies = new CookieContainer();
var handler = new HttpClientHandler();
handler.CookieContainer = cookies;
using (var client = new HttpClient(handler))
{
var uri = new Uri(url);
client.BaseAddress = uri;
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("redirect", "false")
});
HttpResponseMessage response = await client.PostAsync("logoutservice", content);
if (response.IsSuccessStatusCode)
{
var responseBodyText = await response.Content.ReadAsStringAsync();
if (!String.IsNullOrEmpty(responseBodyText))
{
Console.WriteLine("Unsuccessful Logout.Bonita bundle may not have been started, or the URL is invalid.");
return;
}
Console.WriteLine("Successfully Logged out.");
}
else
{
Console.WriteLine("Logout Error" + (int)response.StatusCode + "," + response.ReasonPhrase);
}
}
}
public async void GetProcesses()
{
var handler = new HttpClientHandler();
Cookie ok = new Cookie("Set-Cookie:",strCookietoPass);
handler.CookieContainer.Add(collection);
using (var client = new HttpClient(handler))
{
var builder = new UriBuilder("http://localhost/bonita/API/bpm/process");
builder.Port = 8080;
var query = HttpUtility.ParseQueryString(builder.Query);
query["p"] = "0";
query["c"] = "10";
builder.Query = query.ToString();
Uri uri= new Uri(builder.ToString());
client.BaseAddress = uri;
HttpResponseMessage response = await client.GetAsync(uri.ToString());
if (response.IsSuccessStatusCode)
{
var responseBodyText = await response.Content.ReadAsStringAsync();
if (String.IsNullOrEmpty(responseBodyText))
{
Console.WriteLine("Unsuccessful GetProcesses.Bonita bundle may not have been started, or the URL is invalid.");
return;
}
Console.WriteLine("Successfully GetProcesses:" + responseBodyText);
}
else
{
Console.WriteLine("GetProcesses Error" + (int)response.StatusCode + "," + response.ReasonPhrase);
}
}
}
}
}
I had the same problem (401 errors) for every single non-GET request.
I finally got through this by looking to the CSRF documentation:
http://documentation.bonitasoft.com/7.4?page=csrf-security
(See the "Is there an impact on REST API calls?" section)
After succesfull login, you have to put a special header in your request:
key: X-Bonita-API-Token
value: the one you got after your login (check the relevant cookie)

Facing Issue While Integrating Google Login Button With Java Application

I am working on Hybris Technology. It is nothing but the Java only. So I am trying to Integrate Google Login Button with my Java Application.
I am following this tutorial. Here is my code What I am doing
Front Part --
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js">
</script>
<script type="text/javascript">
(function () {
var po = document.createElement('script');
po.type = 'text/javascript';
po.async = true;
po.src = 'https://plus.google.com/js/client:plusone.js?onload=start';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(po, s);
})();
</script>
<div id="signinButton">
<span class="g-signin" data-scope="https://www.googleapis.com/auth/plus.login"
data-clientid="*****************************"
data-redirecturi="postmessage"
data-accesstype="offline"
data-cookiepolicy="single_host_origin"
data-callback="signInCallback">
</span>
</div>
<div id="result"></div>
<script type="text/javascript">
function signInCallback(authResult) {
if (authResult['code']) {
// Hide the sign-in button now that the user is authorized, for example:
$('#signinButton').attr('style', 'display: none');
// Send the code to the server
$.ajax({
type: 'GET',
url: '/store/en/login/lnregister',
contentType: 'application/octet-stream; charset=utf-8',
success: function(result) {
// Handle or verify the server response if necessary.
// Prints the list of people that the user has allowed the app to know
// to the console.
console.log(result);
if (result['profile'] && result['people']){
$('#results').html('Hello ' + result['profile']['displayName'] + '. You successfully made a server side call to people.get and people.list');
} else {
$('#results').html('Failed to make a server-side call. Check your configuration and console.');
}
},
processData: false,
data: authResult['code']
});
} else if (authResult['error']) {
// There was an error.
// Possible error codes:
// "access_denied" - User denied access to your app
// "immediate_failed" - Could not automatially log in the user
// console.log('There was an error: ' + authResult['error']);
}
}
</script>
Here I am using ajax to call my controller function lnregister.
#RequestMapping(value = "/lnregister", method = RequestMethod.GET)
public String doLnRegister(#RequestHeader(value = "referer", required = false) final String referer, final RegisterForm form,
final BindingResult bindingResult, final Model model, final HttpServletRequest request,
final HttpServletResponse response, final RedirectAttributes redirectModel) throws CMSItemNotFoundException
{
final Gson gson = new Gson();
final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
final String APPLICATION_NAME = "HybrisProject";
final HttpTransport TRANSPORT = new HttpTransport()
{
#Override
protected final LowLevelHttpRequest buildRequest(final String arg0, final String arg1) throws IOException
{
// YTODO Auto-generated method stub
return null;
}
};
final String CLIENT_ID = "************************";
final String CLIENT_SECRET = "*******************";
// Create a state token to prevent request forgery.
// Store it in the session for later validation.
final String state = new BigInteger(130, new SecureRandom()).toString(32);
request.getSession().setAttribute("state", state);
// Read index.html into memory, and set the Client ID,
// Token State, and Application Name in the HTML before serving it.
try
{
return new Scanner(new File("index.html"), "UTF-8").useDelimiter("\\A").next()
.replaceAll("[{]{2}\\s*CLIENT_ID\\s*[}]{2}", CLIENT_ID).replaceAll("[{]{2}\\s*STATE\\s*[}]{2}", state)
.replaceAll("[{]{2}\\s*APPLICATION_NAME\\s*[}]{2}", APPLICATION_NAME);
}
catch (final FileNotFoundException e2)
{
// YTODO Auto-generated catch block
e2.printStackTrace();
}
if (!request.getParameter("state").equals(request.getSession().getAttribute("state")))
{
response.setStatus(401);
gson.toJson("Invalid state parameter.");
}
final String gPlusId = request.getParameter("gplus_id");
String code = null;
try
{
code = request.getReader().toString();
}
catch (final IOException e1)
{
// YTODO Auto-generated catch block
e1.printStackTrace();
}
try
{
// Upgrade the authorization code into an access and refresh token.
final GoogleTokenResponse tokenResponse = new GoogleAuthorizationCodeTokenRequest(TRANSPORT, JSON_FACTORY, CLIENT_ID,
CLIENT_SECRET, code, "postmessage").execute();
// Create a credential representation of the token data.
final GoogleCredential credential = new GoogleCredential.Builder().setJsonFactory(JSON_FACTORY).setTransport(TRANSPORT)
.setClientSecrets(CLIENT_ID, CLIENT_SECRET).build().setFromTokenResponse(tokenResponse);
// Check that the token is valid.
final Oauth2 oauth2 = new Oauth2.Builder(TRANSPORT, JSON_FACTORY, credential).build();
final Tokeninfo tokenInfo = oauth2.tokeninfo().setAccessToken(credential.getAccessToken()).execute();
// If there was an error in the token info, abort.
if (tokenInfo.containsKey("error"))
{
response.setStatus(401);
return gson.toJson(tokenInfo.get("error").toString());
}
// Make sure the token we got is for the intended user.
if (!tokenInfo.getUserId().equals(gPlusId))
{
response.setStatus(401);
return gson.toJson("Token's user ID doesn't match given user ID.");
}
// Make sure the token we got is for our app.
if (!tokenInfo.getIssuedTo().equals(CLIENT_ID))
{
response.setStatus(401);
return gson.toJson("Token's client ID does not match app's.");
}
// Store the token in the session for later use.
request.getSession().setAttribute("token", tokenResponse.toString());
return gson.toJson("Successfully connected user.");
}
catch (final TokenResponseException e)
{
response.setStatus(500);
return gson.toJson("Failed to upgrade the authorization code.");
}
catch (final IOException e)
{
response.setStatus(500);
return gson.toJson("Failed to read token data from Google. " + e.getMessage());
}
}
Here my Question is Am I going in right direction. Is it a proper way to connect java application with Google Login API. My Front View is working fine. When I click on google+ button, request also going to my controller. But There in backend side I am getting error. I am not pasting this error bacause error like NullPointerException or like that.
My Question is I am going in a proper way or not. If It is not, then what is the right way. Please help me.
You are making this very hard for yourself, and re-implementing too much.
Read http://krams915.blogspot.se/2011/02/spring-security-3-openid-login-with_13.html
You just need to ensure your Provider and UserDetailsService do what you need.

Categories