I am building login application using OAuth2 and spring boot microservice. The challenge I facing is implementing two factor authentiation. Once the user enters credentials when gets successful then before sending
access token to frontend it should call another microservice to send sms to phone number which is present in access token.
Currently I am using flag IS_TFA_ENABLED=Y if Y then making other ajax call to send sms to phone number received in access token,But i want this sms service to be called at server side only after credentials are validated successfullyand shoot another sms service call.
Any suggestion how to implement this ?
front end code is below
$.ajax({
type: "POST",
url: "http://localhost:8095/oauth2-service/oauth/token",
data: "username="+username+"&password="+password+"&grant_type=password",
beforeSend: function(request) {
request.setRequestHeader("Authorization", "Basic "+btoa("clientId:password"));
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
},
success: function(msg){
**if(JSON.parse(JSON.stringify(msg)).is_tfa_enabled=="Y") {**
**var email_two_fa_url = "http://localhost:8095/user-service/users/"+JSON.parse(JSON.stringify(msg)).id
+"/emails/"+JSON.parse(JSON.stringify(msg)).userName+"/2fa";
var mobile_two_fa_url = "http://localhost:8095/user-service/users/"+JSON.parse(JSON.stringify(msg)).id
+"/mobilenumbers/"+JSON.parse(JSON.stringify(msg)).mobile+"/2fa";
var verify_2fa_url = "http://localhost:8095/user-service/users/"+JSON.parse(JSON.stringify(msg)).id
+"/codes/";**
sessionStorage.setItem("email_two_fa_url",email_two_fa_url);
sessionStorage.setItem("mobile_two_fa_url",mobile_two_fa_url);
sessionStorage.setItem("verify_2fa_url",verify_2fa_url);
sessionStorage.setItem("access_token", JSON.parse(JSON.stringify(msg)).access_token);
sessionStorage.setItem("refresh_token", JSON.parse(JSON.stringify(msg)).refresh_token);
if(JSON.parse(JSON.stringify(msg)).tfa_default_type=="SMS") {
two_fa_url = mobile_two_fa_url;
} else {
two_fa_url = email_two_fa_url;
}
send2facode(two_fa_url, function() {
$("#myModal").modal('show');
});
}else{
localStorage.setItem("access_token", JSON.parse(JSON.stringify(msg)).access_token);
localStorage.setItem("refresh_token", JSON.parse(JSON.stringify(msg)).refresh_token);
window.location.reload("permissions.html");
}
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
$(".alert-danger").show();
}
});
I propose to develop two authentication services:
The first service provide authentication user login/password. If the
credentials are corrects, it sends the SMS, saves the code in the
database for verification and returns back a temporary token that
contains only the user id and one authorization for the second service
(SECOND_FACT_AUTH for example). It is possible to insert the code
inside the to ken to avoid the access to database.
The second service secured by the authorization "SECOND_FACT_AUTH"
that checks the code in database or inside the token according to
where you store it, then it generates the traditional authentication and
refresh tokens.
Related
I have a ReactJS front end website which uses AWS Cognito for authentication, this is working fine, I can sign in, up, out, etc. My back end is a set of Java web services running in Docker containers in AWS Fargate all behind an Elastic Load Balancer.
I noticed that in the ELB, you can add Authentication to the listeners which will check the HTTP header for the jwt token and authenticate it before forwarding to the relevant micro service. I've come a cross an issue where when I set the 'Authenticate...' rule, it comes back with an error that I need to add a client secret. I can't add a client secret to my Cognito setup because I'm accessing it from ReactJS and apparently Javascript doesn't work with Cognito with Client Secret added.
So if I can't use this method, I need some way of authenticating HTTPS requests when they get to my Java microservices. From my Java service, it feels like I need to somehow access AWS Cognito to check the user session but that feels wrong.
Any ideas how this should work?
Thanks
You can consider to use pure JS to authenticate with AWS Cognito without client secret which is an optional. I did create a App Client without Client Secret and it did work.
Reference: https://docs.aws.amazon.com/cognito/latest/developerguide/authentication.html
// Amazon Cognito creates a session which includes the id, access, and refresh tokens of an authenticated user.
var authenticationData = {
Username : 'username',
Password : 'password',
};
var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails(authenticationData);
var poolData = {
UserPoolId : 'us-east-1_ExaMPle',
ClientId : '1example23456789'
};
var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
var userData = {
Username : 'username',
Pool : userPool
};
var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function (result) {
var accessToken = result.getAccessToken().getJwtToken();
/* Use the idToken for Logins Map when Federating User Pools with identity pools or when passing through an Authorization Header to an API Gateway Authorizer */
var idToken = result.idToken.jwtToken;
},
onFailure: function(err) {
alert(err);
},
});
Also, as you are using ReactJS, you can try Amplify:
https://aws-amplify.github.io/docs/js/authentication
I understand that while you have so many layers and sometimes you want to configure it as you want, you can try to make yourself a simple authenticating function with AWS Lambda.
I have an app A(client), which makes a web-service GET call to App B(server). App B is using web page authentication redirect for all these incoming web service get request calls. AppB is processing GET request some thing like:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
// code lines
//....
..
String login_URL = "https://sometestsite.com/pagLogin";
StringBuffer baseURL = request.getRequestURL();
String query = request.getQueryString();
String encReturnURL = URLEncoder.encode(baseURL.toString() + "?" + query, "UTF-8");
String final_URL = login_URL + encReturnURL ;
Cookie[] cookies = request.getCookies();
if ((cookies == null) || (cookies.length == 0))
{
response.sendRedirect(noCookieURL);
return;
}
String cookieValue= null;
for (int i = 0; i < cookies.length; i++)
{
Cookie thisCookie = cookies[i];
String cookieName = thisCookie.getName();
if (cookieName == null)
{
//logger.info("cookieName is null");
}
//logger.info("cookieName is " + cookieName);
if (cookieName.equals("myCookie"))
{
cookieValue = thisCookie.getValue();
break;
}
}
String ESEncypt = esGatekeeper.esGatekeeper(cookieValue,"password");
if(ESEncrypt satisfies some condition){
// construct output message and response
String output = "{Some JSON message}";
response.setContentType("application/json");
response.getWriter().append(output);
}
}
I am working on appA(client) side, to make requests to appB(server), appA is java, REST, spring boot based micro-service.
Question: How can I successfully get through this authentication?
1) In appA I have tried using ApacheHttpClient, and URLConnection to establish a connection to url: https://sometestsite.com/pagLogin. and tried to send cookies to server appB using setRequestProperty("cookieName","value") on HttpURLConnection.
2) as appB uses sendRedirect in case no cookie exist, How to (is it a best practice to) send login crendentials along with get request from appA to appB, so that appB can forward those details when it makes sendRedirect call.
The setup seems to have implemented OAuth2.0 Authorization Code grant type. In OAuth2.0 terminology, the server hosting the login page is called "authorization server", the server hosting the API or any website requiring authentication is called "resource server" and the application trying to consume the api is called "client".
Now, if the "Client" acts on behalf of a user (consider an end user wants to log into a web application), the setup you described is the right setup. Any one of Authorization Code grant type, Implicit grant type and Resource Owner Password Credential grant type can be used and each of them will redirect the user to a login page as you mentioned above.
But when the "Client" is not acting on behalf of any individual user (e.g. a batch job) as in your case, the grant type to be used is Client Credential grant type. Here no redirection to login page will happen. Instead the "client" will directly communicate with the "authorization server" with a client id and client secret and the "authorization server" will return an access code. The client can the communicate with the api in "resource server" with the access code (may be through cookie).
Refer to Client Credential grant type description in RFC 6749 OAuth2.0 specification for complete details.
Does anyone can help me to get a solution for authenticate with a backend server ? I am logging in in my platform with a google account and I post the id_token (using ajax).
var msg = $.ajax({type: "POST", url: "controller/action", data: token, async: false}).responseText;
if (msg=="ok"){
window.location = "controller/action";
}
else {
window.location = "controller/action";
}
Now, I want to authenticate the token in order to save user information (name, image,email) in database.
I see this https://developers.google.com/identity/sign-in/web/backend-auth. Is there a way to use it?
Send get Request in any RestClient and replace xyz with your token:-
https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=xyz
Once you get Response in restclient then simply assemble this get request in your convenient language. Get request in grails see this
hope it helps you
I have been trying hard to work this out for login authentication using angular as client and jersey exposed as rest web service at backend.
Here is what I achieved from last three days.
Angular code to capture email and password:
myApp.controller('loginController',['$scope','$http', function($scope, $http)
{
$scope.email = "" ;
$scope.password = "" ;
$scope.loginForm = function(){
alert("login controller called");
console.log($scope.email);
console.log($scope.password);
var encodedString = 'email=' +
encodeURIComponent($scope.email) +
'&password=' +
encodeURIComponent($scope.password);
$http({
method:'POST',
url: 'rs/loginResource',
data: encodedString,
headers: {'Content-Type' : 'application/x-www-form-urlencoded'}
});
};
}]);
Java rest code:
#Path("/loginResource")
public class LoginResource {
public LoginResource() {
}
#POST
#Consumes("application/x-www-form-urlencoded")
public void login(#FormParam("email") String email,
#FormParam("password") String password) {
System.out.println("Email is: " + email); //prints output
System.out.println("Password is: " + password); //prints output
}
}
And now my question is where to go from here after getting the POST data from form submit. As you can see I am just printing the values rather I would like to check the email and password against database(oracle). How would I go about it? Shall I use simple connection class and dao or go for JPA which I haven't learned yet - what is the learning curve for it?
Is there any design pattern involved? Usually I use Dao and pojo if its plain java but I am new to rest api that too struggling with angular. I hardly find any examples on vanilla java+angular where most of them are based on spring+angular.
Generally login goes like this:
Client calls server with login details
Server verifies login details against the database, if valid, sets up a session. If invalid, the server will return a very generic error response. Important to not give the client any info about which part of the submission was wrong (gives attackers more info).
For this you'll want to read into sessions. Here are some links:
https://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/http/HttpSession.html
https://medium.com/opinionated-angularjs/techniques-for-authentication-in-angularjs-applications-7bbf0346acec#.z4vdsyrty
There's plenty of information on this problem on the internet.
Also, for generic REST APIs authentication will usually happen in the form of a token. The flow looks a little different:
Client calls server with some sort of auth info
The server generates a token using something like Json Web Tokens and returns it to the client. Generally these have an expiry. The server might also expire all other tokens for the user.
The client sends the token, generally as a header, with every future request.
There's lots of ways to encrypt a password when sending it from client -> server. Here's a simple one I suggest you try: RESTful Authentication
I want to build a client/server application using Sencha Touch 2 on the client side and Java/hibernate/MSSQL database technology on the server side. To get started I created the client side user login frame.Now i need help to implement the server side of the application.
That is, to take the username/password and send it to the server and validate if the login is correct or not. Can somebody please help me to achieve this part. I am using Tomcat as the container for my server side.
It is very Easy,Below code not totally working ,but it will give you just an idea,to start.
Create Login form in sencha touch(Login.js)
Write a Login Controller in sencha touch which is responsible for making Ajax request from front end to backend. This controller should contain below line of code inside a function.
var user = Ext.getCmp('user_name');
var pass = Ext.getCmp('password');
// For security purpose you should always pass credntial in encrypted format
var param = {user_name:user,password:pass};
var jsonData = JSON.stringify(param);
Ext.Ajax.request({
url: 'http://server_ip:8080/backend/authenticate',
jsonData : param,
success: function(response){
Ext.Msg.Alert(null,"Login Successfule");
//You can write your own logic to display any other screen
}
failure : function(error){
Ext.Msg.Alert(null,"Unable to authenticate user");
}
});
3.Now prepare you back end using any frame work in java let say Spring MVC.
4. Write a controller
#Controller
public class AuthenticateController{
#RequestMapping(value="authenticate",method = RequestMethod.POST,consumes="application/json",produces="application/json")
#ResponseBody
public String authenticateUser((#RequestBody String json){
//Now by using json data you can verify user by querying DB,and return your own message.
}
}