Eduard Lebedyuk · May 11, 2018 go to post

Security (link under construction)
Using JSON - how do you implement a logon?

What are the licensing issues?

For password authenticated web applications it is possible by following these steps:

  1. All brokers effectively have Parameter UseSession = 1;
  2. REST web application and client web application allow only authenticated (i.e. password) access.
  3. REST web application and client web application have reasonable Session timeout (i.e. 900, 3600).
  4. REST web application and client web application have the same GroupById value.
  5. REST web application and client web application have the same cookie path.

If all these conditions are met, user would only consume one license slot per session and perform only one login.

How do you prevent users hacking restful calls that they have no access to?

Authentication as a start, SQL security for basic data access checks, app-level checks for the most specific cases

Eduard Lebedyuk · May 11, 2018 go to post

Sessions or No Sessions 

REST mainly disallows sessions as a mechanism of data transfer. Stateless as stated in REST dissertation by Roy Fielding has three aims:

  • visibility
  • reliability
  • scalability

Visibility is improved because a monitoring system does not have to look beyond a single request datum in order to determine the full nature
of the request. In my opinion that's the most important one and it mainly deals with storing session data in between requests.

Let's say you provide a newsfeed API. There's a lot of news so users get them by pages of 10 elements. Clients can access news in two different ways:

  1. http://host/api/news/next - in this case the server remembers last page of news the client requested and returns the next one. That's not stateless.
  2. http://host/api/news/:pagenmumber - in this case client remembers last page of news he requested and asks for the next one by incrementing page number by 1. That's stateless.

Reliability is improved because it eases the task of recovering from partial failures. Where partial failure is defined as (from Waldo J,
Wyant G, Wollrath A, Kendall S. A Note on Distributed Computing.):

Partial failure is a central reality of distributed computing. Both the local and the distributed world contain components that are subject to periodic failure.

In the case of local computing, such failures are either total, affecting all of the entities that are working together in an application, or detectable by some central resource allocator (such as the operating system on the local machine).

This is not the case in distributed computing, where one component (machine, network link) can fail while the others continue. Not only is the failure of the distributed components independent, but there is no common agent that is able to determine what component has failed and inform the other components of that failure, no global state that can be examined that allows determination of exactly what error has occurred.

In a distributed system, the failure of a network link is indistinguishable from the failure of a processor on the other side of that link.

Sessions as an authentication/authorisation mechanism do not affect Reliability.

Scalability is improved because not having to store state between requests allows the server component to quickly free resources, and
further simplifies implementation because the server doesn't have to manage resource usage across requests. Not relevant in our case as Session still gets created, just destroyed immediately after the request is done.


To sum up: REST APIs can use sessions as authentication mechanism, but not as a data transfer mechanism.

Eduard Lebedyuk · May 10, 2018 go to post

Maybe remove $zf calls?

Here's sample code:

 ClassMethod Test()
{
//Create new Gateway connection object
set gc=##class(%SQLGatewayConnection).%New()
if gc=$$$NULLOREF quit $$$ERROR($$$GeneralError,"Cannot create %SQLGatewayConnection.")
  
//Make connection to target DSN
set pDSN="Cache Samples"
set usr="_system"
set pwd="SYS"
set sc=gc.Connect(pDSN,usr,pwd,0) 
if $$$ISERR(sc) w !, $SYSTEM.OBJ.DisplayError(sc) QUIT 0
if gc.ConnectionHandle="" W !, $$$ERROR($$$GeneralError,"Connection failed") QUIT
  
set sc=gc.AllocateStatement(.hstmt) 
if $$$ISERR(sc) w !, $SYSTEM.OBJ.DisplayError(sc) QUIT 0
  
//Prepare statement for execution
set pQuery= "select Name, DOB from Sample.Person WHERE Name %STARTSWITH ?"
set sc=gc.Prepare(hstmt,pQuery) 
if $$$ISERR(sc) w !, $SYSTEM.OBJ.DisplayError(sc) QUIT 0
//Bind Parameters
set sc=gc.BindParameter(hstmt,1,1,1,12,30,0,30)
if $$$ISERR(sc) w !, $SYSTEM.OBJ.DisplayError(sc) QUIT 0
set var = "A"
set sc=gc.SetParameter(hstmt,$LB(var),1)
if $$$ISERR(sc) w !, $SYSTEM.OBJ.DisplayError(sc) QUIT 0
//Execute statement
set sc=gc.Execute(hstmt)
if $$$ISERR(sc) w !, $SYSTEM.OBJ.DisplayError(sc) QUIT 0
//Get list of columns returned by query
set sc=gc.DescribeColumns(hstmt, .columnlist) 
if $$$ISERR(sc) w !, $SYSTEM.OBJ.DisplayError(sc) QUIT 0
 
//display column headers delimited by ":"
set numcols=$listlength(columnlist)-1 //get number of columns
for colnum=2:1:numcols+1 {
    Write $listget($listget(columnlist,colnum),1),":"
   }
write !
 
//Return first 20 rows 
set sc=gc.Fetch(hstmt)
if $$$ISERR(sc) w !, $SYSTEM.OBJ.DisplayError(sc) QUIT 0
s rownum=1
while((gc.sqlcode'=100) && (rownum<=20)) {
       for ii=1:1:numcols {
       s sc=gc.GetData(hstmt, ii, 1, .val)
       w " "_val
       if $$$ISERR(sc) break
       }
       s rownum=rownum+1
  write !
  set sc=gc.Fetch(hstmt)
if $$$ISERR(sc) break
   }
    
  //Close cursor and then disconnect
set sc=gc.CloseCursor(hstmt)
if $$$ISERR(sc) w !, $SYSTEM.OBJ.DisplayError(sc) QUIT 0
  
set sc=gc.Disconnect()
  
quit sc
}

Check BindParameter method and EnsSQLTypes for SQL types macro definitions. Varchar maybe.

You can also try to call PutData method and similar methods (by passing parts of stream there).

Eduard Lebedyuk · May 10, 2018 go to post

You can convert object into json:

 set sc = ##class(%ZEN.Auxiliary.jsonProvider).%ObjectToJSON(obj)

And work with that.

Eduard Lebedyuk · May 10, 2018 go to post

You can use zwrite to display object contents to a terminal:

set msg = ##class(class).%OpenId(Id)
zwrite msg
set obj = msg.GetAt(1)
zwrite obj
Eduard Lebedyuk · May 10, 2018 go to post

The problem with write *-3 is that it is currently added to a system code. I'm searching for a better solution.

Eduard Lebedyuk · May 9, 2018 go to post

#2 limit yourself to 2048 char.

Nowadays it's fine. Most browsers work with long URLs.

So is your redirect just URL or  URL?urplarams=...... 

It's  URL?urplarams=...... 

One parameter is 5000+ symbols long.

Eduard Lebedyuk · May 9, 2018 go to post

I think that using ExportTasks and ImportTasks methods of %SYS.TaskSuper class as proposed by @Sean Connelly and @John Murray would be a better solution as:

  • It would not override system tasks
  • It would produce readable XML
Eduard Lebedyuk · May 9, 2018 go to post

MONEXT is an include file, you can see it in %SYS namespace.

You can map it to your namespace (in SMP - Namespaces - Routine mappings).

Eduard Lebedyuk · May 9, 2018 go to post

ServerSideRedirect  doesn't work in that context (OAuth authentication) unfortunately.

I also tried setting LOCATION header directly (via SetHeader method) - in that case I get the same truncated output.

Eduard Lebedyuk · May 9, 2018 go to post

You can export/import  ^SYS("Task","TaskD") global directly, which contains task definitions data.

Some properties are computed (i.e. LastFinished), and could probably cause this error.

Try to export/import minimal set of columns.

Alternative approach would be writing code to generate tasks.

Eduard Lebedyuk · Apr 26, 2018 go to post

Should they have access?

The best solution here is restricting access.

InterSystems security model allows for a customizable access management.

Application building/testing/deployment tasks could be fully automated and so not require human intervention at all.

Eduard Lebedyuk · Apr 22, 2018 go to post

Classes only.

Each method, that could be called from a terminal is documented with a sample call.

Eduard Lebedyuk · Apr 22, 2018 go to post

Try

chrome --headless --disable-gpu --print-to-pdf https://www.google.com/

Referenced article also shows several examples.

Chrome could be called with $zf(-1) function.

Eduard Lebedyuk · Apr 20, 2018 go to post

That looks like GZIP. Can you save response stream as a file and reopen it as a %Stream.FileCharacterGzip?

Eduard Lebedyuk · Apr 20, 2018 go to post

All properties names are written in:

 Write $$$ZENJSONPROP(tPropName,pFormat)_": {"

Write $$$ZENJSONPROP(tPropName,pFormat)_":["

To get current property XMLNAME parameter call this:

  Write $$$comMemberArrayGet(tClass,$$$cCLASSproperty,tPropName,$$$cPROPparameter,"XMLNAME")