Worklight - How to check if a client is already logged in - authentication

LoginViewModel.js
function login(){
var username='worklight';
var password = 'worklight';
var invocationData = {
adapter : "AuthenticationAdapter",
procedure : "submitAuthentication",
parameters : [ username, password ]
};
adapterAuthRealmChallengeHandler.submitAdapterAuthentication(invocationData, {});
AdapterAuthRealmChallengeProcessor.js
var adapterAuthRealmChallengeHandler = WL.Client.createChallengeHandler("AdapterAuthRealm");
adapterAuthRealmChallengeHandler.isCustomResponse = function(response) {
if (!response || !response.responseJSON || response.responseText === null) {
return false;
}
if (typeof(response.responseJSON.authRequired) !== 'undefined'){
return true;
} else {
return false;
}
};
adapterAuthRealmChallengeHandler.handleChallenge = function(response){
var authRequired = response.responseJSON.authRequired;
if (authRequired == true){
window.location = "#login";
alert(response.responseJSON.errorMessage);
} else if (authRequired == false){
adapterAuthRealmChallengeHandler.submitSuccess();
window.location = "#Home";
}
};
AuthenticationAdapter-impl.js
function onAuthRequired(headers, errorMessage){
errorMessage = errorMessage ? errorMessage : null;
return {
authRequired: true,
errorMessage: errorMessage
};
}
function submitAuthentication(username, password){
var userIdentity = {
userId: username,
displayName: username,
attributes: {
foo: "bar"
}
};
WL.Server.setActiveUser("AdapterAuthRealm", userIdentity);
return {
authRequired: false
};
}
I am not able to set setActiveUser. How to set it and get it. Above wat I have to done for maintaining session. Is it right way to do it. Sometimes I got error Illegal State: Cannot change identity of an already logged in user in realm 'Adapter AuthRealm'. The application must logout first. If I tried to set it null first then it causes my application to enter an infinite loop of attempting to authenticate. Any idea why I would see this behavior?
Anything I am doing wrong?
please help mi out.

Check the SO answer for Worklight logout does not clear active user
Try reloading app onSuccess of Logout.
WL.Client.logout("AdapterAuthRealm",{
onSuccess: function(){ WL.Client.reloadApp(); },
onFailure: function(){ WL.Logger.debug("Error on logout");}
});
And you can check realm is authenticated or not by using wl client Java script API
WL.Client.isUserAuthenticated("AdapterAuthRealm");

Related

Do I still need users in user pool if I want to work Custom Authentication workflow in AWS Cognito?

I have a webservice which validates user/pwd and returns true/false (valid/invalid). I am trying to leverage Custom Authentication Workflow of AWS Cognito to integrate with the webservice.
I read through the docs and came across the define, create and verify lambda triggers and I tried those as follows:
Define trigger:
exports.handler = async (event) => {
if (!event.request.session || event.request.session.length === 0) {
event.response.challengeName = "CUSTOM_CHALLENGE";
event.response.failAuthentication = false;
event.response.issueTokens = false;
} else if (event.request.session.length === 1) {
// If we passed the CUSTOM_CHALLENGE then issue token
event.response.failAuthentication = false;
event.response.issueTokens = true;
} else {
// Something is wrong. Fail authentication
event.response.failAuthentication = true;
event.response.issueTokens = false;
}
return event;
};;
Create Trigger:
exports.handler = async (event) => {
if (event.request.challengeName == 'CUSTOM_CHALLENGE') {
event.response.publicChallengeParameters = {};
event.response.privateChallengeParameters = {};
}
return event;
}
Verify Trigger:
exports.handler = async (event, context) => {
//call webservice using "event.userName" and "event.request.challengeAnswer" (password)
var result = <bool-result-received-from-webservice>
event.response.answerCorrect = result;
return event;
};
The JS client looks like this:
Amplify.configure({
Auth: {
region: 'dd',
userPoolId: 'eeee',
userPoolWebClientId: 'ffff',
authenticationFlowType: 'CUSTOM_AUTH'
}
})
let user = await Auth.signIn(username)
.then(u => {
console.log(u); //(1) TOKENS ARE ALREADY CREATED HERE WITHOUT VERIFYING PASSWORD. NOT SURE.
if (u.challengeName === 'CUSTOM_CHALLENGE') {
console.log("responding to challenge..");
// to send the answer of the custom challenge
Auth.sendCustomChallengeAnswer(u, password)
.then(u2 => {
console.log("after responding to challenge...");
console.log(u2); //(2) NEW TOKENS ARE CREATED HERE. NOT SURE.
return u2;
})
.catch(err => {
console.log("ERROR with Challenge:");
console.log(err);
});
} else {
console.log("no challenge needed..");
return u;
}
})
.catch(err => {
console.log("ERROR with sign-in:..");
console.log(err);
});
I mentioned 1 and 2 in the comments above. Not sure if it's behaving correctly.
If the username is not in the "users" list of "user pool", it throws it as invalid login. Is it possible to validate username/password only through webservice having no "users" in the "user pool"?

Firebase authentication in Ionic not working

I am trying to build an ionic application which does basic authentication.
My registration system is working in terms of pushing data into my Firebase URL and logging the user in, adding user into the Login and Auth system, but my login is not doing proper Authentication. Note, this is just the first step - my aim is the check if the user's UID matches the UID I have stored in firebaseurl/uids/firebasekey/uid. I get this error:
Login Failed! TypeError: Cannot read property 'email' of undefined(…)
this is the error that is caught.
Even though I know the user with that email exists in the Firebase instance.
Here is my LoginCtrl:
.controller('LoginCtrl', ['Auth', '$state', '$location', '$scope', '$rootScope', '$firebaseAuth', '$window',
function (Auth, $state, $location, $scope, $rootScope, $firebaseAuth, $window) {
// check session
//$rootScope.checkSession;
// Create a callback to handle the result of the authentication
$scope.user = {
email: this.email,
password: this.password
};
$scope.validateUser = function (user) {
$rootScope.show('Please wait.. Authenticating');
console.log('Please wait.. Authenticating');
var email = this.user.email;
var password = this.user.password;
/* Check user fields*/
if (!email || !password) {
$rootScope.hide();
$rootScope.notify('Error', 'Email or Password is incorrect!');
return;
}
/* All good, let's authentify */
Auth.$authWithPassword({
email: email,
password: password
}).then(function (authData) {
console.log(authData);
$rootScope.userEmail = user.email;
$window.location.href = ('#/app/meals');
$rootScope.hide();
}).catch(function (error) {
console.log("Login Failed!", error);
if (error.code == 'INVALID_EMAIL') {
$rootScope.notify('Invalid Email Address');
}
else if (error.code == 'INVALID_PASSWORD') {
$rootScope.notify('Invalid Password');
}
else if (error.code == 'INVALID_USER') {
$rootScope.notify('Invalid User');
}
else {
$rootScope.notify('Oops something went wrong. Please try again later');
}
$rootScope.hide();
//$rootScope.notify('Error', 'Email or Password is incorrect!');
});
};
this.loginWithGoogle = function loginWithGoogle() {
Auth.$authWithOAuthPopup('google')
.then(function (authData) {
$state.go($location.path('app/meals'));
});
};
this.loginWithFacebook = function loginWithFacebook() {
Auth.$authWithOAuthPopup('facebook')
//Use the authData factory
.then(function (authData) {
$state.go($location.path('app/meals'));
});
};
}
])
And here is my SignupCtrl:
.controller('SignUpCtrl', [
'$scope', '$rootScope', '$firebaseAuth', '$window', 'Auth',
function ($scope, $rootScope, $firebaseAuth, $window, Auth) {
$scope.user = {
firstname: this.firstname,
lastname: this.lastname,
email: "",
password: ""
};
$scope.createUser = function () {
var firstname = this.user.firstname;
var lastname = this.user.lastname;
var email = this.user.email;
var password = this.user.password;
//https://www.firebase.com/docs/web/guide/login/password.html
if (!email || !password) {
$rootScope.notify("Please enter valid credentials");
return false;
}
$rootScope.show('Please wait.. Registering');
$rootScope.auth.$createUser(
{email: email, password: password})
.then(function (user) {
console.log('user is created');
$rootScope.hide();
$rootScope.userEmail = user.email;
var usersRef = new Firebase('https://foodsharingapp.firebaseio.com/users');
var keyRef = usersRef.push({
'uid': user.uid,
'email': email,
'firstname': firstname,
'lastname': lastname
});
var uidRef = new Firebase('https://foodsharingapp.firebaseio.com/uids/' + user.uid + '/' + keyRef.key());
uidRef.set({'registered': true});
$window.location.href = ('#/app/meals');
}, function (error) {
console.log('error unfortunately');
$rootScope.hide();
if (error.code == 'INVALID_EMAIL') {
console.log('invalid email');
$rootScope.notify('Invalid Email Address');
}
else if (error.code == 'EMAIL_TAKEN') {
console.log('email taken');
$rootScope.notify('Email Address already taken');
}
else {
console.log('not sure what happened');
$rootScope.notify('Oops something went wrong. Please try again later');
}
});
}
Auth.$onAuth(function (user) {
if (user === null) {
console.log("Not logged in yet");
} else {
console.log("Logged in as", user.uid);
}
$scope.user = user; // This will display the user's name in our view
});
}
])
And here is my Auth factory:
app.factory('Auth', ['rootRef', '$firebaseAuth',function(rootRef, $firebaseAuth){
return $firebaseAuth(rootRef);
}]);
And here is my app.js related to Auth:
$rootScope.userEmail = null;
$rootScope.baseUrl = 'https://foodsharingapp.firebaseio.com/';
var authRef = new Firebase($rootScope.baseUrl);
$rootScope.auth = $firebaseAuth(authRef);
$rootScope.authData = authRef.getAuth();
$rootScope.logout = function() {
authRef.unauth();
$rootScope.authDataCallBack;
};
$rootScope.checkSession = function() {
if ($rootScope.authData) {
console.log("User " + authData.uid + " is logged in with " + authData.provider);
$rootScope.userEmail = user.email;
$window.location.href = ('#/app/meals');
} else {
console.log("No session so logout");
$rootScope.userEmail = null;
$window.location.href = '#/auth/signin';
}
}
$rootScope.authDataCallBack = function(authData) {
if ($rootScope.authData) {
console.log("User " + authData.uid + " is logged in with " + authData.provider);
} else {
console.log("User is logged out");
$window.location.href = '#/auth/signin';
}
};
//Listens for changes
authRef.onAuth($rootScope.authDataCallback);
Note, the other issue is that the onAuth function in the app.js function is not working.
How should I clean up my code? What am I doing wrong? I am using a bunch of tutorials etc and I don't think the right way.
I have figured out the issue.
$rootScope.userEmail = user.email;
I was calling this line when user is actually undefined as a variable (though $scope.user has been defined).
login controller code
function ($scope, $stateParams, $firebaseAuth, $state) {
$scope.user = {
'email': '',
'password': ''
};
$scope.signIn = function(){
$scope.errorBox = '';
const promise = firebase.auth().signInWithEmailAndPassword($scope.user.email, $scope.user.password);
promise.then(resp => {
$state.go('zazzycoinsActivities');
})
.catch(err => {
$scope.$apply(function(){
$scope.errorBox = err.message;
});
});
};
}
this might work for you too it worked for me......

Handle challenge function not called when logging in after logout

I have created angular service, where I'm registering challengeHandler this way:
azureChallengeHandler = WL.Client.createChallengeHandler(realm);
azureChallengeHandler.isCustomResponse = function (response) {
...
};
azureChallengeHandler.handleChallenge = function (response) {
...
};
So i'm logging in with this function:
WL.Client.login(realm, options)
And the first time it works ok, isCustomResponse gets called, returns "true", then handleChallenge gets called.
But after logging out with this function:
WL.Client.logout(realm, options)
When I try to login again, isCustomResponse gets called and still returns "true", but handleChallenge is not firing.
How can I fix that?
After calling WL.Client.reloadApp() or reloading app itself I can login again, but it's not a suitable solution.
UPDATE:
Here is adapter code:
function onAuthRequired(headers) {
return customLoginResponse(true, false, false);
}
function customLoginResponse(authRequired, azureTokenRequired, wrongTenant) {
return {
authRequired: authRequired,
azureTokenRequired: azureTokenRequired,
realm: 'AzureAuth',
wrongTenant: wrongTenant
};
}
function onLogout(){
WL.Server.setActiveUser("AzureAuth", null);
WL.Logger.debug("Logged out");
}
function submitLogout(uuid, orgId, ssogroup){
WL.Server.invokeProcedure({
adapter: "AzureTokenSqlAdapter",
procedure: "removeRefreshToken",
parameters: [uuid, orgId, ssogroup]
});
onLogout();
}
function submitLogin(uuid, orgId, ssogroup, code) {
var tokenObject = getTokens(code);
if (tokenObject.id_token) {
var jwtParsed = parseJWT(tokenObject.id_token);
var tenantId = jwtParsed.tid;
var invocationResult = WL.Server.invokeProcedure({
adapter: "AzureTokenSqlAdapter",
procedure: "checkTenant",
parameters: [orgId, tenantId]
});
if (!invocationResult.tenantRegistered) {
return customLoginResponse(true, true, true);
}
}
return authUser(tokenObject, uuid, orgId, ssogroup);
}
And here is the client code:
function azureAuthService($q, _, $state) {
var loginPromise;
azureChallengeHandler = WL.Client.createChallengeHandler(realm);
//first response after protected call
azureChallengeHandler.isCustomResponse = function (response) {
if (!response || !response.responseJSON || response.responseText === null) {
return false;
}
return response.responseJSON.realm == realm;
};
//when isCustomResponse returns true
azureChallengeHandler.handleChallenge = function (response) {
WL.Logger.debug("challenge handler -- handleChallenge");
var authRequired = response.responseJSON.authRequired;
var azureTokenRequired = response.responseJSON.azureTokenRequired;
var wrongTenant = response.responseJSON.wrongTenant;
if (wrongTenant) {
loginPromise.reject('wrong tenant');
} else if (authRequired && azureTokenRequired) {
fullLogin();
} else if (authRequired) {
fastLogin();
} else {
loginPromise.resolve();
}
};
azureChallengeHandler.handleFailure = function (error) {
console.log('failure');
console.log(error);
};
return {
init: init,
login: login,
logout: logout
};
function init(config) {
ssogroup = config.ssogroup;
orgId = config.orgId;
}
function login() {
loginPromise = $q.defer();
WL.Client.login(realm, {
onSuccess: function(info) {
loginPromise.resolve();
},
onFailure: function(error) {
loginPromise.reject();
}
});
return loginPromise.promise;
}
function logout() {
var logoutPromise = $q.defer();
var invocationData = {
adapter : 'AzureAuth',
procedure : 'submitLogout',
parameters : [device.uuid, orgId, ssogroup]
};
WL.Client.invokeProcedure(invocationData).then(function () {
WL.Client.logout(realm, {
onSuccess: function () {
logoutPromise.resolve();
},
onFailure: function () {
logoutPromise.reject();
}
});
}, function () {
logoutPromise.reject();
});
return logoutPromise.promise;
}
}
fastLogin and fullLogin is functions that perform some work and finally call
var options = {
parameters: [device.uuid, orgId, ssogroup, transitionAuthObject.requestToken],
adapter: "AzureAuth",
procedure: "submitLogin"
};
azureChallengeHandler.submitAdapterAuthentication(options);
Can't see your fullLogin() and fastLogin() methods so it's hard to say for sure. Make sure that you're calling challengeHandler's submitSuccess() or submitFailure() methods after successful/failed authentication. The authentication framework keeps a queue of requests/responses that require authentication. After successful/failed authentication you need to invoke submitSuccess/submitFailure on challenge handler in order for authentication framework to remove your requests from queue and process it. In case you're not doing so the request remains in the queue and once you're sending a new request that triggers authentication it is put into queue but not handled since there's another request already waiting for authentication.

MobileFirst 7.0 combining Authentication and Java SQL Adapter fails

Im trying to combine Java UserAdapter and Adapter-based authentication
I want to get the users list after authenticated, but it fails
On server-side, Adapter-based authentication, AuthenticationAdapter-impl.js
function onAuthRequired(headers, errorMessage) {
errorMessage = errorMessage ? errorMessage : null;
return {
authRequired: true,
errorMessage: errorMessage
};
}
function submitAuthentication(username, password){
if (username==="admin" && password === "admin"){
var userIdentity = {
userId: username,
displayName: username,
attributes: {
foo: "bar"
}
};
WL.Server.setActiveUser("AdapterAuthRealm", userIdentity);
return {
authRequired: false
};
}
return onAuthRequired(null, "Invalid login credentials");
}
function listUsers() {
var resourceRequest = new WLResourceRequest("/adapters/UserAdapter/", WLResourceRequest.GET);
return resourceRequest.send();
}
function onLogout() {
WL.Server.setActiveUser("AdapterAuthRealm", null);
WL.Logger.debug("Logged out");
}
And on client-side,
function listUsers(){
busyIndicator.show();
var invocationData = {
adapter : "AuthenticationAdapter",
procedure: "listUsers",
parameters: []
};
WL.Client.invokeProcedure(invocationData, {
onSuccess: listUsersSuccess,
onFailure: listUsersFailure
});
}
function listUsersSuccess(result){
WL.Logger.debug("Feed retrieve success");
busyIndicator.hide();
WL.Logger.debug(JSON.stringify(result));
if (result.responseJSON.length > 0){
displayUsers(result.responseJSON);
} else {
listUsersFailure();
}
}
function listUsersFailure(result){
WL.Logger.error("Feed retrieve failure");
busyIndicator.hide();
WL.SimpleDialog.show("Banking Application", "Service not available. Try again later.", [
{
text : 'Reload',
handler : WL.Client.reloadApp
},
{
text: 'Close',
handler : function() {}
}
]);
}
It returns onFailure response
WLResourceRequest is a client side API so you CAN NOT use it on an adapter since the adapter runs on the server.
You should update your listUsers function (client side) as follows:
function listUsers(){
busyIndicator.show();
var resourceRequest = new WLResourceRequest("/adapters/UserAdapter/", WLResourceRequest.GET);
resourceRequest.send().then(listUsersSuccess).fail(listUsersFailure);
}
Update
You can protect your Java Adapter methods by using the #OAuthSecurity annotation.
UserAdapter.java
#GET
#Path("/protectePath")
#OAuthSecurity(scope="YourRealm")
public String myProtectedMethod() {
// your code here
return "your-response";
}

Getting server error when using custom login method

I am trying to test the custom login method functionality, so this is my client:
Meteor.loginWithCode = function(phone, code) {
Accounts.callLoginMethod({
methodArguments: [{
hascode: true,
phone: phone,
code: code
}],
userCallback: function loginCallback (error, result) {
console.log(error, result);
}
});
};
And this is the server:
Accounts.registerLoginHandler('login', function(loginRequest) {
var user = Meteor.users.findOne({phone: loginRequest.phone});
if(user.code !== loginRequest.code) {
return null;
}
var stampedToken = Accounts._generateStampedLoginToken();
var hashStampedToken = Accounts._hashStampedToken(stampedToken);
Meteor.users.update(user._id,
{$push: {'services.resume.loginTokens': hashStampedToken}}
);
return {
id: user._id,
token: stampedToken.token
};
});
Why am I getting
Exception while invoking method 'login' Error: A login method must specify a userId or an error
When I do Meteor.loginWithCode('123456789', '123');?
You should return userId not id :
Accounts.registerLoginHandler('login', function(loginRequest) {
...
...
return {
userId: user._id,
token: stampedToken.token
};
})
If login was unsuccessful then pass error instead userId.
Proof:
if (!result.userId && !result.error)
throw new Error("A login method must specify a userId or an error");
Line 255-256