Article
· Nov 2, 2023 9m read

The Security Package - Managing Applications Programatically

Here in %SYS, we have already examined users, resources, and roles. Now that we know how to set all of that up, we should give it a purpose. Next we will talk about applications! As you may expect, we will see various identical class methods defined here that we have seen in the previous classes. However, some of them will have some tiny yet significant differences.

One of those key distinctions in the Security.Applications package is the presence of three separate types of applications that you can define. Depending on which kind of application we are working with, some properties of this class may or may not apply. For example, if you are defining a client application, there is no reason to care about a CSP login or error page. The sort of application is determined by the application’s Type property as follows:

Type Property

Application Type

1

System (Reserved; do not use)

2

CSP Application (Default; this includes REST applications)

4

Privileged Routine Application

8

Client Application

We will start examining this class with its Get method and later proceed with a test case we are all familiar with: 

set sc = ##class(SYSTEM.Applications).Get("/csp/sys",.props)

It will put the properties of an application named /csp/sys into the props array. If we look closer at that array’s Description property, we will notice that this is nothing but the System Management Portal. Whereas some properties such as Name, NameSpace, and Description are easy to understand, others appear slightly more complicated. That is why we will examine the properties related to securing your application in more detail.

Property

Description

AutheEnabled

Defines which authentication mechanisms are enabled

AutoCompile

When turned on with a CSP file being more recent than its compiled class, it gets recompiled

CSPZENEnabled

If turned on, the application processes CSP or Zen pages

CSRFToken

Prevents login CSRF attacks

ChangePasswordPage

A Password change page where the browser gets redirected if the user's password requires alterations

ClientApplications

Timestamps and hashes of valid executables for client applications

CookiePath

Scope of session cookies for CSP

DeepSeeEnabled

Defines whether Analytics is enabled for the namespace or not

Description

Description of the application

DispatchClass

If defined, all requests get sent to this page

Enabled

Defines whether or not the application is enabled

ErrorPage

Page to be displayed if there is an error generating the CSP page

EventClass

Specifies the class that handles CSP application events

GroupById

Used to group authentication of multiple applications

InbndWebServicesEnabled

Defines whether the application processes web services

IsNameSpaceDefault

Defines whether this is the default application for this namespace

JWTAccessTokenTimeout

Timeout in seconds for JWT access tokens

JWTAuthEnabled

Defines whether or not JWT authentication is enabled

JWTRefreshTokenTimeout

Defines the timeout for JWT refresh tokens in seconds

LockCSPName

When true, it serves only those pages where the URL matches the CSP page’s URL

LoginPage

Login page to redirect users to if they need to log in

MatchRoles

Mapping of matching roles to target roles

Name

Name of this application

NameSpace

Namespace the application runs in

Package

Package that is automatically prefixed to all CSP files

Path

Physical path to CSP files on the server

PermittedClasses

Can be used to limit the classes available for usage in this application

Recurse

Specifies whether to look for CSP pages in subfolders of the physical path or not

RedirectEmptyPath

Specifies whether to use FHIR-standard redirects or not

Resource

Optional resource required for this application

Routines

List of routines that can invoke the application for privileged routine applications

ServeFiles

Specifies the way to handle static files

ServeFilesTimeout

Determineds how long to cache static files

SessionScope

SameSite value for CSP session cookies

SuperClass

Default superclass for this application’s CSP pages

Timeout

Default session timeout

Type

Application Type

UseCookies

Specifies whether to use cookies for CSP session management or not

UserCookieScope

SameSite value for cookies created by calls to %CSP.Response.SetCookie()

iKnowEnabled

Defines whether or not iKnow is enabled for this application

Although the AutheEnabled property is crucial, it can be hard to understand. It is a numeric value that tells IRIS which authentication methods are enabled for the application. Each authentication mechanism has a numeric value associated with it. If more than one is enabled, AutheEnabled is the sum of those values. For example, imagine your password authentication is 32, whereas unauthenticated value is 64. In this case, to enable both, set AutheEnabled to 96.

Fortunately, you can use the AutheEnabled property’s DisplayToLogical function to help you figure out the right number. When you provide that function with a list of keywords separated by commas in any order, it calculates the right number for you. These keywords are not case sensitive, so consider the following line of code:

write ##class(Security.Applications).AutheEnabledDisplayToLogical("two-factor sms,password")

It will write 1048608. Thus, if you set the AutheEnabled property for an application to that number, it will enable password authentication and two-factor SMS authentication. The keywords you can use include password, LDAP, two-factor SMS, two-factor time-based one-time password, unauthenticated, login cookie, Kerberos, and delegated. If the DisplayToLogical function returns a -1, it means you have provided an invalid keyword.

Concerning security, we should also look at the Resource property. If you have read the previous articles in this series, you should already be familiar with setting up resouces, adding them to roles, and granting those roles to users. If a resource is defined here, only users who have permission to use that resource will be able to access the application.

If you are using login cookies for authentication, it is crucial to establish the cookie path properly. Suppose you have two applications, /mycsp/app1 and /mycsp/app2. If the cookie path on those two applications is set to /mycsp, then that cookie will provide access to both applications if the user is permitted to use both of them. It means that if they have already logged into one of those applications, they will not have to log in again to access the other one. However, if the cookie paths are set to /mycsp/app1 and /mycsp/app2 respectively, then the user will have to log in to each application separately.

ChangePasswordPage, LoginPage, ErrorPage, and DispatchClass should all be set to a class name if you use them. The class used for ChangePasswordPage should be the one that extends with %CSP.PasswordChange. The LoginPage should have the extension %CSP.Login, and the ErrorPage should end with %CSP.Error. All those details will define how the user will get redirected to their respective events. The DispatchClass, which should extend with %CSP.REST, is used for REST APIs and will send all requests to that %CSP.REST class.

MatchRoles sets up the matching roles for an application. When a user logs into your application, if they have the matching role, they will be assigned the target ones. It is a set of colon-delimited lists of roles separated by commas if this property is defined as follows:

MatchRole1:Target1:Target2,MatchRole2:Target1

When a user with MatchRole1 logs in, they will be granted both roles: Target1 and Target2, while using this application. If you want a role to be permanently assigned while using the application, which is the equivalent of setting it as an “Application Role” in the management portal, you need to define it without a matching role beforehand. If my MatchRoles property is set to :TargetRole, then TargetRole is always granted while using this application.

There are also three properties that control JSON Web Token authentication. They allow you to set whether or not JWT authentication is enabled, and how many seconds the access token and refresh token stay valid before timing out.

Despite giving the impression of being one of the most complicated classes we have examined, this one actually has the most traditional set of methods!

  • set sc = ##class(Security.Applications).Get("myapp",.props) will get the app properties named myapp and stored in props.
  • set sc = ##class(Security.Applications).Create("mynewapp",.props) will create a new application called mynewapp with the properties stored in the props array.
  • set sc = ##class(Security.Applications).Modify("myapp",.props) will modify an existing application, changing its properties to match those in the props array.
  • set exists = ##class(Security.Applications).Exists("myapp",.handle,.sc) will set exists to 1 if the application myapp exists or to 0 if there was an error or the application did not exist. It will also return the application object to handle and set a status code in sc that will tell you if an error occurred (remember to check whether or not exists got set to 0).
  • set sc = ##class(Security.Applications).Delete("myapp") will delete the application called myapp
  • set sc = ##class(Security.Applications).Export("myapps.xml",.numexported,"*",1) will export the applications to an XML file. You can replace the * with a comma-separated list of applications to export only those applications. You can also change the number to export only certain application types. In this case, 1 indicates CSP applications. After you run this set, numexported will be replaced with the number of applications exported.
  • set sc = ##class(Security.Applications).Import("myapps.xml",.numimported,1) will import applications from an XML file and set numimported to the number of applications imported. Setting the last argument to 0 will not actually import anything, but will still set numimported to the number of applications that could have been imported.

There is also a Copy method that was not present in some of the other classes in this package. If you want to copy the application myapp to a new application called mynewapp with a description of “My new application”, you can quickly do that with the following line of code:

set sc = ##class(Security.Applications).Copy("myapp","mynewapp","My new application.")

This is likewise one of the few classes in the Security package that has an instance method, IsPublic(). It returns a boolean telling you whether or not the application is public, so it is very straightforward.

Additionally, there are also three class queries defined in this class. The Detail query takes a comma-separated list of app names (or a * for all) and an application type, and returns all of the properties of any resulting applications. If you want a more concise data set, the List query only returns the name, namespace, whether or not the application is the default for its namespace, and whether or not it is enabled. Besides, it returns type, resource, authentication methods, whether or not the application is a system-defined application, and the dispatch class. The NamespaceList query takes a comma-separated list of namespaces (again, * for all) and gives you only the name and path for applications in the specified namespaces.

Now that we have wrapped up applications, it’s time to put these building blocks together and work on our own REST API! Look out for my next article for details.

Discussion (1)2
Log in or sign up to continue