Hi all,
Since mibuso's been such a huge help to me in the past, I want to share my recent NAV-solution with you guys.
What I wanted was to publish a page as a web service from NAV, but I wanted to have user-authentication. NAV didn't provide a reasonable way to do this,
and on the other hand I wanted to let specific users only access specific records.
Example scenario:
- The record Sales Quotes is published as a web service (a new page)
- I want users to be able to log in with their own Customer No. and a password, from a front-end (eg. php or java)
- Users may only access their own records
Of course, we could just filter the new Sales Quote -page with Sell-to Cust. = Customer, but this is unacceptable because by removing the filter a bad-guy could access everyones records.
So instead, my solution:
- The record for the web service -page is temporary
- Authentication details are provided in a filter-field
- The accepted users are listed in a separate NAV table
- The records (to publish) are written to the temporary table in runtime, in C/AL, based on the credentials provided
A. STEPS TO SET THIS UP:
1. A new Page, with the source table you want to publish (eg. Sales Quote), SourceTableTemporary = yes.
2. A Users-table, with User Name and Hash-fields (eg. sha12) if you want to do it right, or a password-field if moving plaintext-passwords is ok for you.
3. Fields "User Name" and Hash in the record you want to publish. These fields are only used by the front-end to provide credentials - they needn't have any values in the record itself.
4. Proper trigger code in OnFindRecord() of the web service Page. Here's an example which builds the temporary record, ie. the records to give out in the web service:
OnFindRecord(Which : Text) : Boolean
{
// trim since filter can contain ''
userName := DELCHR( GETFILTER("User Name"), '<>', '''');
userHash := DELCHR( GETFILTER(Hash), '<>', '''');
// function which compares the given credentials to the ones in the User-table.
// Be sure to use SETRANGE and not SETFILTER when looking for the User with hash,
// and check that you only get one record as a result. We don't want Hash='*' to work.
IF NOT cu.userAuthentication(userName, userHash) THEN
BEGIN
DELETEALL(FALSE);
EXIT(FALSE);
END;
IF (userName <> '') THEN // credentials accepted
BEGIN
salesHeader.COPYFILTERS(Rec); // could potentially be some filters worth copying
salesHeader.SETRANGE(Hash); // don't care about auth-filters anymore
salesHeader.SETRANGE("User Name", userName);
salesHeader.SETRANGE("Document Type", salesHeader."Document Type"::Order);
IF salesHeader.FIND('-') THEN
REPEAT
Rec.TRANSFERFIELDS(salesHeader);
Rec.INSERT(FALSE);
UNTIL salesHeader.NEXT() = 0;
Rec.RESET;
EXIT(Rec.FIND(Which));
END;
EXIT(FALSE);
}
B. STEPS TO USE THIS:
1. Set the filters you want for the record, eg. Salesperson Code = FUU
2. Set filter-value for the fields User Name and Hash
3. Request records from the web service
Java-
example for setting the authentication-filters WebServiceFilter userFilter = new WebServiceFilter();
userFilter.setField(WebServiceFields.USER_NAME);
userFilter.setCriteria(userName);
WebServiceFilter hashFilter = new WebServiceFilter();
hashFilter.setField(WebServiceFields.HASH);
hashFilter.setCriteria(userHash);
ArrayList<WebServiceFilter> filters1 = new ArrayList<WebServiceFilter>();
filters1.add(userFilter);
filters1.add(hashFilter);
WebServiceList salesQuotes = serviceCall.readMultiple(filters1, null, 0);
C. STEPS TO TEST THIS
To see whether authentication works and the web service provides (only the) records as we want it to.
1. Set working credentials as filters in the web service pages OnOpenPage
OnOpenPage()
SETFILTER("User Name", '2000');
SETFILTER(Hash, '%1', 'C984106E1276A..');
2. Run the Page. If everything is working as it should, you should now see the records which will be provided when these login-credentials are provided.
Also test what happens when you clear the filter.
3. Remember to clear the OnOpenPage-trigger-code before you publish this, otherwise this users records will be shown.
I hope this proves useful for others too!
Have a great week!
J