IBM MobileFirst remove collection without initialize - ibm-mobilefirst

Is there any API to remove a collection without initialize the collection?
Here is my scenario. There is a KeyCollection that store credential from server to initialize the other collection. User has to key in credential to unlock the KeyCollection. It is use to cater forget password scenario that do not wipe off(destroy) the whole database which is request by our client. User forgot the password of a collection, so the system will only remove the Keycollection and init with new user credential and get the credential from server again.
I unable to remove a collection without initialize it, and below is the code that remove the collection from device. Is there any alternative to cater the scenario or remove the collection in order for me to .init again?
.Get
Use get to create an accessor to the collection. You must call init before you call get otherwise the result of get is undefined (From IBM Website)
var options = {};
WL.JSONStore.get(collectionName).removeCollection().then(function (removeCollectionReturnCode) {
}).fail(function (errorObject) {
});

There is the choice of the use of the destroy method, but this removes more than the just the collection. It could be removing more than you would like by the scenario described.
http://www-01.ibm.com/support/knowledgecenter/SSHS8R_7.0.0/com.ibm.worklight.apiref.doc/html/refjavascript-client/html/WL.JSONStore.html%23destroy?lang=en
Completely wipes data for all users, destroys the internal storage,
and clears security artifacts.
More details here: http://www-01.ibm.com/support/knowledgecenter/SSHS8R_7.0.0/com.ibm.worklight.dev.doc/devref/c_jsonstore_api_concepts.html?lang=en
Destroy Completely wipes data for all users, destroys the internal
storage, and clears security artifacts. The destroy function removes
the following data:
All documents.
All collections.
All stores. For more information, see JSONStore multiple user support.
All JSONStore metadata and security artifacts. For more information, see JSONStore security.
An example of use:
WL.JSONStore.destroy()
.then(function () {
// Handle success.
})
.fail(function (errorObject) {
// Handle failure.
});
I hope this info helps,

You will need to have the password before you can do any operation with the database. You could just hash the password in a separate database and if the person has forgotten it just change the password with a temporary password or a new password of the user's choosing.

Related

Session lost after redirect SAML: may be different webapps?

I am fairly new to webapps programming, so I thought of asking here.
I am implementing the SAML2 protocol in an open source app (namely OFBiz) but I am encountering a problem related to session loss after the protocol made its course.
I am following these steps to implement the protocol. Suppose ofbizwebsite.com is the URL of the site.
Installed a custom plugin named SAMLIntegration which exposes the ACS page and the logic for login. To my understanding, a plugin (gradle) is like an indipendent java project, which translates to a new set of resources for the application (the plugin enables, for example, to visit ofbizwebsite.com/SAMLIntegration and setup some resources).
Exposed the ACS page to ofbizwebsite.com/SAMLIntegration/control/acs, as well as metadata ofbizwebsite.com/SAMLIntegration/control/metadata.jsp
Created the logic for login. Basically, an entity called UserLogin is saved in the session and recovered by a "checker" to understand if an user is logged in. Suppose that this checker is a HTTP WebEvent handler which can be called by any resource requiring authentication.
Now, the problem. If redirect the user to a resource on SAMLIntegration (for example ofbizwebsite.com/SAMLIntegration/control/aview or any ofbizwebsite.com/SAMLIntegration/control/* by calling response.sendRedirect("aview")) check works and login is preserved. Visiting any resource (for example ofbizwebsite.com/aplugin/control/anotherview) by navigating the application does not preserve the session.
OFBiz use internally a mechanism for preserving the userLogin between webapps, by creating an HashMap between and UUID and a UserLogin object. The UUID is passed between two different resources, appending this key to each path (so ofbizwebsite.com/aplugin/control/anotherview?externalKey=THEEFFECTIVEUUID)
To my understanding, changing from ofbizwebsite.com/SAMLIntegration/control/* to ofbizwebsite.com/aplugin/control/* determine a session loss. So, my idea was to replace the UUID mechanism with SAML2. However, I do not know how to solve this problem.
In particular, I would like to execute a SAML request each time the checker function is executed. If I can't find the user in the session, a SAML request is fired. However, my problem is HOW to manage the response. Normally, I would redirect it to the acs ofbizwebsite.com/SAMLIntegration/control/acs. Doing so, however, does not allow me to handle the response in the checker function, as the control is passed to another servlet by an external request (the SAML response fired by the IdP). Should I provide a different acs for each different path? (so one for SAMLIntegration and one for aplugin?) And, even if this was the case, how can I return the control to the checker function which has invoked the SAML request?
Here you go for installing the Shibboleth HTTPD module: https://pad.nereide.fr/SAMLWithShibboleth
You also need this method somewhere in OFBiz (I recommend LoginWorker.java, but you can put it where you want). It allows to use the externalAuthId of the userLogin for authentication, with the uid returned by the sso:
public static String checkShibbolethRequestRemoteUserLogin(HttpServletRequest request, HttpServletResponse response) {
LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher");
Delegator delegator = dispatcher.getDelegator();
// make sure the user isn't already logged in
if (!LoginWorker.isUserLoggedIn(request)) {
String remoteUserId = (String) request.getAttribute("uid"); // This is the one which works, uid at Idp, remoteUserId here
if (UtilValidate.isNotEmpty(remoteUserId)) {
//we resolve if the user exist with externalAuthId
String userLoginId = null;
GenericValue userLogin;
try {
List<GenericValue> userLogins = delegator.findList("UserLogin",
EntityCondition.makeConditionMap("externalAuthId", remoteUserId, "enabled", "Y"),
null, null, null, true);
userLogin = userLogins.size() == 1 ? userLogins.get(0) : null;
} catch (GenericEntityException e) {
Debug.logError(e, module);
return "error";
}
if (userLogin != null) {
userLoginId = userLogin.getString("userLoginId");
}
//now try to log the user found
return LoginWorker.loginUserWithUserLoginId(request, response, userLoginId);
}
}
return "success";
}
You also need to have this method as an OFBiz preprocessor in the webapp controllers. I suggest to have a look at common-controller.xml.
Finally you need the configs that redirect to the SSO page if no session. That should do the job, at least it works for them...
Finally I recommend https://www.varonis.com/blog/what-is-saml in case of need.

Get user info when someone runs Google Apps Script web app as me

I have a standalone Google Apps Script deployed as a web app. The app is executed as me, because I want it to access files stored on my Drive, and because I want it to generate Google Sheets files that have some ranges protected from the user that are still editable by the script. However, I want these files to be segregated into folders, and each folder is assigned to a user, so I need to know who the user is each time the app runs.
Session.getActiveUser().getEmail() doesn't work since the web app is deployed as me and not as the user. My other thought was to make the app "available to everyone, even anonymous" (right now it's just "available to everyone") to skip Google's login screen, and use some kind of third-party authentication service or script. Building my own seems like overkill because this seems like it should already exist, but so far my research has only turned up things like Auth0 which seem incompatible with my simple Google Apps Script-based app, or else I'm too inexperienced to figure out how to use them.
Does anyone have a suggestion for how to authenticate users for this kind of web app? Preferably something that comes with a beginner-friendly tutorial or documentation? Or, is there another way for me to find out who's running the app while still executing it as myself?
I am so new to this I'm not even sure I'm asking this question in the right way, so suggested edits are taken gratefully.
I can think of two ways you might approach this where the Web App is deployed to execute as the user accessing it:
Scenario A: Create a service-account to access files stored on your Drive and to generate google sheets.
Scenario B: Create a separate Apps Script project deployed as an API Executable and call its functions from the main Web App.
These methods are viable but there are a number of pros and cons to each.
Both require OAuth2 authentication, but that bit is fairly easy to handle thanks to Eric Koleda's OAuth2 library.
Also, in both scenarios, you'll need to bind/link your main Apps Script project to a GCP project and enable the appropriate services, in your case Google Sheets and Google Drive APIs (see documentation for more details).
For Scenario A, the service account must be created under the same GCP project. For Scenario B, the secondary Apps Script project for the API executable must also be bound to the same GCP project.
Issues specific to Scenario A
You'll need to share the files and folders you want to access/modify (and/or create content in) with the service account. The service account has it own email address and you can share google drive files/folders with it as you would with any other gmail account.
For newly created content, permissions could be an issue, but thankfully files created under a folder inherit that folder's permissions so you should be good on that front.
However, you'll have to use the REST APIs for Drive and Sheets services directly; calling them via UrlFetch along with the access token (generated using the OAuth2 library) for the Service Account.
Issues specific to Scenario B
You'll need to setup a separate Apps Script project and build out a public API (collection of non-private functions) that can be called by a 3rd party.
Once the script is bound to the same GCP project as the main Web App, you'll need to generate extra OAuth2 credentials from GCP console under the IAM (Identity Access Management) panel.
You'll use the Client ID and Client Secret, to generate a refresh token specific to your account (using the OAuth2 library). Then you'll use this refresh token in your main Web App to generate the requisite access token for the API executable (also using the OAuth2 library). As in the previous scenario, you'll need to use UrlFetch to invoke the methods on the API Executable using the generated access token.
One thing to note, you cannot use triggers within the API executable code as they are not allowed.
Obviously, I've glossed over a lot of the details but that should be enough to get you started.
Best of luck.
Now that I've implemented TheAddonDepot's suggested Scenario B successfully, I wanted to share a few details that might help other newbies.
Here's what the code in my web app project looks like:
function doGet(e) {
// Use user email to identify user folder and pass to var data
var userEmail = Session.getActiveUser().getEmail();
// Check user email against database to fetch user folder name and level of access
var userData = executeAsMe('getUserData', [userEmail]);
console.log(userData);
var appsScriptService = getAppsScriptService();
if (!appsScriptService.hasAccess()) { // This block should only run once, when I authenticate as myself to create the refresh token.
var authorizationUrl = appsScriptService.getAuthorizationUrl();
var htmlOutput = HtmlService.createHtmlOutput('Authorize.');
htmlOutput.setTitle('FMID Authentication');
return htmlOutput;
} else {
var htmlOutput = HtmlService.createHtmlOutputFromFile('Index');
htmlOutput.setTitle('Web App Page Title');
if (userData == 'user not found') {
var data = { "userEmail": userEmail, "userFolder": null };
} else {
var data = { "userEmail": userData[0], "userFolder": userData[1] };
}
return appendDataToHtmlOutput(data, htmlOutput);
}
}
function appendDataToHtmlOutput(data, htmlOutput, idData) { // Passes data from Google Apps Script to HTML via a hidden div with id=idData
if (!idData)
idData = "mydata_htmlservice";
// data is encoded after stringifying to guarantee a safe string that will never conflict with the html
var strAppend = "<div id='" + idData + "' style='display:none;'>" + Utilities.base64Encode(JSON.stringify(data)) + "</div>";
return htmlOutput.append(strAppend);
}
function getAppsScriptService() { // Used to generate script OAuth access token for API call
// See https://github.com/gsuitedevs/apps-script-oauth2 for documentation
// The OAuth2Service class contains the configuration information for a given OAuth2 provider, including its endpoints, client IDs and secrets, etc.
// This information is not persisted to any data store, so you'll need to create this object each time you want to use it.
// Create a new service with the given name. The name will be used when persisting the authorized token, so ensure it is unique within the scope
// of the property store.
return OAuth2.createService('appsScript')
// Set the endpoint URLs, which are the same for all Google services.
.setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
// Set the client ID and secret, from the Google Developers Console.
.setClientId('[client ID]')
.setClientSecret('[client secret]')
// Set the name of the callback function in the script referenced
// above that should be invoked to complete the OAuth flow.
.setCallbackFunction('authCallback')
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getScriptProperties())
// Enable caching to avoid exhausting PropertiesService quotas
.setCache(CacheService.getScriptCache())
// Set the scopes to request (space-separated for Google services).
.setScope('https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/spreadsheets')
// Requests offline access.
.setParam('access_type', 'offline')
// Consent prompt is required to ensure a refresh token is always
// returned when requesting offline access.
.setParam('prompt', 'consent');
}
function authCallback(request) { // This should only run once, when I authenticate as WF Analyst to create the refresh token.
var appsScriptService = getAppsScriptService();
var isAuthorized = appsScriptService.handleCallback(request);
if (isAuthorized) {
return HtmlService.createHtmlOutput('Success! You can close this tab.');
} else {
return HtmlService.createHtmlOutput('Denied. You can close this tab.');
}
}
function executeAsMe(functionName, paramsArray) {
try {
console.log('Using Apps Script API to call function ' + functionName.toString() + ' with parameter(s) ' + paramsArray.toString());
var url = '[API URL]';
var payload = JSON.stringify({"function": functionName, "parameters": paramsArray, "devMode": true})
var params = {method:"POST",
headers: {Authorization: 'Bearer ' + getAppsScriptService().getAccessToken()},
payload:payload,
contentType:"application/json",
muteHttpExceptions:true};
var results = UrlFetchApp.fetch(url, params);
var jsonResponse = JSON.parse(results).response;
if (jsonResponse == undefined) {
var jsonResults = undefined;
} else {
var jsonResults = jsonResponse.result;
}
return jsonResults;
} catch(error) {
console.log('error = ' + error);
if (error.toString().indexOf('Timeout') > 0) {
console.log('Throwing new error');
throw new Error('timeout');
} else {
throw new Error('unknown');
}
} finally {
}
}
I generated the OAuth2 credentials at https://console.cloud.google.com/ under APIs & Services > Credentials > Create Credentials > OAuth Client ID, selecting "Web application". I had to add 'https://script.google.com/macros/d/[some long ID]/usercallback' as an authorized redirect URI, but I apologize as I did this two weeks ago and can't remember how I figured out what to use there :/ Anyway, this is where you get the client ID and client secret used in function getAppsScriptService() to generate the access token.
The other main heads up I wanted to leave here for others is that while Google Apps Scripts can run for 6 minutes before timing out, URLFetchApp.fetch() has a 60s timeout, which is a problem when using it to call a script via the API that takes more than 60s to execute. The Apps Script you call will still finish successfully in the background, so you just have to figure out how to handle your timeout error and call a follow-up function to get whatever the original function should have returned. I'm not sure if that makes sense, but here's the question I asked (and answered) on that issue.

Auth0: Validating id_token/JWT on UI (javascript) level

Update March 2019
I just went over this question again; the Auth0's github code has been updated in December 2018. They are now storing 'access_token','id_token' and 'expire_at' into the object/session, instead of localstorage and using now an 'isLoggedIn' flag to mark if authenticated or not. Check the pull request and these 2 lines in the specific commit: line1 and line2.
If you do not need to re-validate 'id_token' - like I was doing in the original question - that might be an alternative. Otherwise check original question.
Original Question
We are using auth0 for one of our clients. One stack that we are using it for is:
React/Redux UI
NodeJS backend
So we are using a cross origin authentication using implicit grant for that, using JWT with an RS256 algorithm. We also refresh tokens in background using silent authentication.
I was able to validate 'access_token' on the API (nodejs) side using node-jwks-rsa for express
On the UI level, after going through the source code of the auth0-js library I noticed that the "parseHash" method used in their provided react samples, actually validates tokens before we store them in localstorage, ie on successful authentication. Mainly this line in the source code.
Then I used their sample code that allows us to check if a user is authenticated, method isAuthenticated().
Problem with the isAuthenticated() method
From a security perspective, if later on (post authentication) a user of the application decided to manually modify the 'expire_at' label in the storage, they could get away as indeed authenticated. While of course there is additional security checking in our app, I wanted to update this function to validate 'id_token'. So far, I couldn't find any example in auth0's online docs for how to do that.
After digging in their source code I found a method validateToken that is being used. So I decided to leverage it in one of our functions:
import IdTokenVerifier from 'idtoken-verifier'
.... Some code in here ....
reValidateToken() {
return new Promise((resolve, reject) => {
// Both of these are stored in localstorage on successful authentication, using the parseHash method
let id_token = localStorage.getItem('id_token');
let transactionNonce = localStorage.getItem('app_nonce');
this.webAuth.validateToken(id_token, transactionNonce, function(
validationError,
payload
) {
if (!validationError) {
resolve('no validation errors for id_token');
}
if (validationError.error !== 'invalid_token') {
reject(validationError.error);
}
// if it's an invalid_token error, decode the token
var decodedToken = new IdTokenVerifier().decode(id_token);
// if the alg is not HS256, return the raw error
if (decodedToken.header.alg !== 'HS256') {
reject(validationError);
}
});
});
}`
Now, for it to succeed; we store the nonce in localstorage after successful authentication, does this approach create back doors for potential security holes? if it does; what is best practice to validate RS256 JWT id_token(s) on a UI level?

How to modify current user's attributes and persist them through the entire session

I'm authenticating my users using IMAG/Ldap-Bundle (BorisMorel/LdapBundle) and I can't persist any changes made to my User to my LDAP server. But whenever a user logs in, I need to check some stuff locally and add the user's roles according to some rules.
Whenever imag verifies the user/password on my LDAP server, it'll call a service I created that's listening to the 'bind' event. Here's how it goes:
ldap_user_verifier:
class: MyBundle\Service\LdapUserVerifierService
arguments: [ #security.context, #doctrine.orm.default_entity_manager, #twig ]
tags:
- { name: 'kernel.event_listener', event: imag_ldap.security.authentication.pre_bind, method: loadUser }
Note: bind_username_before is set to false, which means LdapUserVerifierService::loadUser will only be called after user's logged in and the User class is loaded on my security.context.
Then I have my LdapUserVerifierService::loadUser like this:
public function loadUser(LdapUserEvent $event) {
$ldapUser = $event->getUser();
[...]
$ldapUser->setLocalUser($localUser);
$ldapUser->addRole('ROLE_USER');
[...]
}
That works great, except for that whenever my user changes page (from /login_check to /dashboard, for example), my modifications to the security.context.getToken().getUser() are lost. My user has a localUser and ROLE_USER associated on /login_check, but it doesn't on /dashboard.
Because my user is not loaded from my app's database, I can't persist it on the database to be loaded on subsequent pagehits and, therefore, can't persist my object changes without saving on another session variable.
Does anyone know what I'm supposed to handle this?
Thank you.
There's just not enough code to provide a better answer, but I don't see where you modify the security.context or the token.
Once you made changes to the user object that you got from the token, you probably need to set this modified user to the token.

Best way to enforce user/authentication state in Ember.JS app

Working on my first EmberJS app. The entire app requires that a user be logged in. I'm trying to wrap my head around the best way to enforce that a user is logged in now (when the page is initially loaded) and in the future (when user is logged out and there is no refresh).
I have the user authentication hooks handled - right now I have an ember-data model and associated store that connects that handles authorizing a user and creating a user "session" (using sessionStorage).
What I don't know how to do is enforce that a user is authenticated when transitioning across routes, including the initial transition in the root route. Where do I put this logic? If I have an authentication statemanager, how do I hook that in to the routes? Should I have an auth route that is outside of the root routes?
Note: let me know if this question is poorly worded or I need to explain anything better, I will be glad to do so.
Edit:
I ended up doing something that I consider a little more ember-esque, albeit possibly a messy implementation. I have an auth statemanager that stores the current user's authentication key, as well as the current state.
Whenever something needs authentication, it simply asks the authmanager for it and passes a callback function to run with the authentication key. If the user isn't logged in, it pulls up a login form, holding off the callback function until the user logs in.
Here's some select portions of the code I'm using. Needs cleaning up, and I left out some stuff. http://gist.github.com/3741751
If you need to perform a check before initial state transition, there is a special function on the Ember.Application class called deferReadiness(). The comment from the source code:
By default, the router will begin trying to translate the current URL into
application state once the browser emits the DOMContentReady event. If you
need to defer routing, you can call the application's deferReadiness() method.
Once routing can begin, call the advanceReadiness() method.
Note that at the time of writing this function is available only in ember-latest
In terms of rechecking authentication between route transitions, you can add hooks to the enter and exit methods of Ember.Route:
var redirectToLogin = function(router){
// Do your login check here.
if (!App.loggedIn) {
Ember.run.next(this, function(){
if (router.currentState.name != "login") {
router.transitionTo('root.login');
}
})
}
};
// Define the routes.
App.Router = Ember.Router.extend({
root: Ember.Route.extend({
enter: redirectToLogin,
login: Ember.Route.Extend({
route: 'login',
exit: redirectToLogin,
connectOutlets: function(router){
router.get('applicationController').connectOutlet('login');
}
}),
....
})
});
The problem with such a solution is that Ember will actually transition to the new Route (and thus load all data, etc) before then transitioning back to your login route. So that potentially exposes bits of your app you don't want them seeing any longer. However, the reality is that all of that data is still loaded in memory and accessible via the JavaScript console, so I think this is a decent solution.
Also remember that since Ember.Route.extend returns a new object, you can create your own wrapper and then reuse it throughout your app:
App.AuthenticatedRoute = Ember.Route.extend({
enter: redirectToLogin
});
App.Router = Ember.Router.extend({
root: Ember.Route.extend({
index: App.AuthenticatedRoute.extend({
...
})
})
});
If you use the above solution then you can cherry pick exactly which routes you authenticate. You can also drop the "check if they're transitioning to the login screen" check in redirectToLogin.
I put together a super simple package to manage session and auth called Ember.Session https://github.com/andrewreedy/ember-session
Please also take a look at :
http://www.embercasts.com/
There are two screencasts there about authentication.
Thanks.