Monday, December 14, 2015

Access Controls to Allow Only Inserting

At some point, you may need to set up a table that allows users the ability to insert records without being able to read the table.

This could arise with a public feedback form in a mobile app that uses ServiceNow as the back-end. Since users are not required to be authenticated to submit feedback, the app might use the same guest account (with no roles) for all users' submissions via JSONv2. Should someone hack the app and discover the guest credentials, you wouldn't want them to be able to obtain historical feedback.

Setup


Suppose you have a table, u_feedback with a single field, u_description (in addition to system fields.)
+---------------+
| u_feedback    |
+---------------+
| u_description |
| ...           |
+---------------+
Along with this, you have a guest account:
Username: app.guest
Password: 1234
If you attempt an insert using JSONv2, an error will be thrown because you haven't created any Access Controls. At this point, app.guest can't read, write, insert, or anything. As shown using curl on the command line:
$ curl --user app.guest:1234 --header 'Content-Type:application/json' --data '{"description":"Great App!"}' "https://instance.service-now.com/u_feedback.do?JSONv2&sysparm_action=insert"
{"error":"Insufficient rights to insert records from the table: u_feedback","reason":null}

Putting in create, write ACLs


Adding two blank Access Controls resolves this.
Access Control 1
Type: record
Operation: create
Name: Feedback [u_feedback] | -- None --

Access Control 2
Type: record
Operation: write
Name: Feedback [u_feedback] | -- None --
The blank create ACL will allow app.guest (or any authenticated user) to insert records into u_feedback. The blank write ACL will allow u_description to have a non-blank value. You may be wondering whether the write ACL also allows anyone to issue a bulk update to the entire table using JSONv2 sysparm_action=update. It does not. Such an update would initiate a query first, which itself would require read privileges that are not granted (yet).

Now, if you attempt an insert again, the record will actually be inserted correctly. But, a different error will be thrown. This is because upon inserts, JSONv2 typically "echoes" the inserted record back to the requester. And, app.guest does not have the ability to read the table.
$ curl --user app.guest:1234 --header 'Content-Type:application/json' --data '{"description":"Great App!"}' "https://instance.service-now.com/u_feedback.do?JSONv2&sysparm_action=insert"
{"error":"Insufficient rights to query records from the table: u_feedback","reason":null}

Allowing JSONv2 to echo inserts


The above error is misleading and annoying even though the insert was successful. In a more advanced situation, like inserting into an Import Set table, you'd want to echo the inserted record because it would contain important status and error messages. To enable echoing without compromising the overall non-readability of our table, you need to allow reading of inserted records only by the same HTTP request that initiated the insertion in the first place.

To do that you'll leverage a global variable that survives through every server-side script executed by a HTTP request, including advanced Business Rules and Access Control scripts. Start by capturing the sys_id of the inserted record in a Business Rule:
Business Rule
Name: Capture sys_id on insert
Table: u_feedback When: before
Insert: true
Advanced: true
Script:
var com_acme_feedback_app_insert_sys_id;
function onBefore(current, previous) {
  com_acme_feedback_app_insert_sys_id =
    current.sys_id.toString();
}
Then, set up a read ACL and leverage the captured sys_id:
Access Control 3
Type: record
Operation: read
Name: Feedback [u_feedback] | -- None --
Advanced: true
Script:
(current.sys_id.toString() ==
  com_acme_feedback_app_insert_sys_id)
When u_feedback is queried immediately following an insertion, com_acme_feedback_app_insert_sys_id will contain the sys_id of the inserted record and ACL script will return true. Any other time the table is queried, the ACL script will return false.

The effect of the Business Rule and Access Control can be seen by issuing another insert request:
$ curl --user app.guest:1234 --header 'Content-Type:application/json' --data '{"description":"Great App!"}' "https://instance.service-now.com/u_feedback.do?JSONv2&sysparm_action=insert"
{"records":[{"u_description":"Great App!","sys_id":"eeaa2f394f5c9a00dd83afdd0210c716" ... }]}

Disclaimer about polluting global namespace


You don't like the global variable com_acme_feedback_app_insert_sys_id, do you. Even with the hacky name-spacing going on? Okay.

Well, it just so happens SnowLib provides a convenient place to stuff these things. So, if you have any of the libraries in your instance, you could instead write to a 'global' variable thusly:
function onBefore(current, previous) {
  SnowLib.feedback_app_insert_sys_id =
    current.sys_id.toString();
}
Of course, now you are just polluting SnowLib. But maybe in the future, SnowLib will contain a nicer facility: a server-side scratchpad, if you will. Until then, the above should work just fine.

Saturday, November 28, 2015

Major update to snow-runner is posted

A major new version of snow-runner, version 0.0.4 is released. Snow-runner allows ServiceNow admins to run server-side JavaScript from the local command line, using Node.js. This makes rapid prototyping, testing, and utility scripting very easy to do: far better than running JavaScript through the Background Script module in a web browser.

Version 0.0.4 includes an interactive mode and a new console mode that makes performance very snappy and makes IDE integration easy. I'll blog on these topics in the near future. For now, head over to GitHub to download the latest.

Thursday, October 29, 2015

Welcome

Driven Snow will focus on advanced ServiceNow development and blogging about the SnowLib project. As the first contributor to the project and to this blog, I am very excited about the possibilities of the platform and the community that is rapidly growing around it.

Why 'Advanced ServiceNow Development'?


I define advanced ServiceNow development as being test-driven (if practical), incorporating good design patterns, and providing a great user experience. There are a couple of reasons such development is important for the platform:

1. Talent


For ServiceNow to remain a viable enterprise platform, it must attract more experienced developers and architects. A critical mass of customers has now gone through a full ServiceNow lifecycle including implementation, upgrades, and add-ons. As the complexity increases and technical debt builds, those customers are learning that their implementations and early project had hidden long-term costs. Those customers will be looking to more experienced individuals to identify and minimize those costs going forward. To attract these types of individuals, the platform requires better tooling and active, open dialog on advanced topics.

At the same time, the platform must retain the talent it already has. Many younger guys I know have fear they are developing too narrow a skill-set. This may be warranted to an extent but my challenge to them is to ask whether they are test-driving their development and following design patterns. Are they following S.O.L.I.D. principles? There is nothing 'narrow' about these pursuits, and such skills are portable to any platform or language in the future.

2. Towering Capabilities


ServiceNow offers an amazing set of pre-built capabilities that developers can combine into amazing business solutions very rapidly. It reminds of how Steve Jobs described the unreleased OS X platform back in 1997:
What [we are] going to be putting in your hands is a system that you can build apps for 5-10 times faster than anything out there. Period. And you can choose to do one of two things or somewhere in the middle with this power. 1. You can make existing complexity apps 5-10 times faster, which means that 3 people really can go into a garage on day one with a concept and come out in the market with a product 6-9 months later.
But rapidity of implementation alone won't advance the platform any further. I think this is actually an area that ServiceNow overemphasizes, with their push into 'citizen development' and the like. Look at how Steve Jobs followed-up on the above concept:
One of the other things you can do with these powerful tools in addition to building a current complexity 5-10 times faster, is build an app you couldn’t build on any platform. And that to me is the most exciting. Build an app you could not build on any other platform, because it’s all about managing complexity, right? You’re developers, you know that. It’s all about managing complexity. It’s like scaffolding, right? You erect some scaffolding, and if you keep going up and up, eventually, the scaffolding collapses of it’s own weight, right? That’s what building software is. It’s how much scaffolding can you erect before the whole thing collapses of its own weight. Doesn’t matter how many people you have working on it. Doesn’t matter if you’re Microsoft with 3-400 people, 500 people on a team. It will collapse under it’s own weight. You read “The Mythical Man-Month”, right? Basic premise of this is a software development project gets to a certain size where it can add one more person. The amount of energy to actually communicate with that person is actually greater than their net contribution to the project so it slows down. So you have local maximum and then it slows down. We all know that about software. It’s about managing complexity. These tools allow you to not have to worry about 90% of the stuff you worry about, so that you can erect your 5 stories of scaffolding, but starting at story number 23 instead of starting at story number 6. You can get a lot higher.
(Transcription from OnStartups.com)
Think about it: if you are a ServiceNow developer, the platform has already taken care of managing an absolute ton of complexity for you. Your peers (you know, the guys getting 'broader' experience) have to solution ORM, integration architecture, navigation systems, a UI system, and more. They have to mix-and-match countless frameworks and roll a lot of their own code just to even come close to the baseline ServiceNow offers. The ECC Queue and the way it works with MID Servers masks a tremendously complex system that you can tap very quickly and easily.

We ServiceNow developers should be using these capabilities to build taller, not just faster. We should be delighting our customers with solutions that could only be built on ServiceNow because they are reaching such towering heights of capabilities.

Closing Remark


I invite you to get in touch, comment, and contribute to SnowLib. Let's help keep the platform strong!