Additional check on cache user authorization

I need to perform additional checks before Cache user logins (let's say in a terminal for simplicity) and allow access only to those, who passed them. How do I do it?

After reading about delegated authentication in docs I created this ZAUTHENTICATE routine:

ZAUTHENTICATE(ServiceName,Namespace,Username,Password,Credentials,Properties) PUBLIC {
 #include %occErrors
 #include %occStatus
 quit $$$ERROR($$$GeneralError,"No access") 
}

and set Password and Delegated as Allowed Authentication Methods   in %Service_Console (it's a windows install)

Expected result: no one can login via the terminal

Actual results: after entering cache user credentials in a terminal prompt user succsessfully logins but in this user plrofile there is:

Last Reason for Failing to Login: ERROR #5001: No access 

audit reports:

2016-02-24 10:10:00.046 %System %Login LoginFailure 7560   dev Error entering the application Programmer mode
  • + 1
  • 0
  • 837
  • 14
  • 0

Comments

Yes, how can I perform additional checks on user login?

What version are you running?  I'd say the expected result is a successful login, assuming correct credentials are entered;  we'll try Delegated authentication first, and if that fails, then try Password.  I just tried this with _SYSTEM, and I got one LoginFailure and one successful Login when I view the Audit log.

For the LoginFailure:

Description:  Programmer mode login failure

 

Error message:  No access [ZAUTHENTICATE+1^ZAUTHENTICATE:%SYS]

Service name: %Service_Console

Login routine:  Programmer mode

 

What you described is what I would expect would happen.  If you're looking to restrict access based on code in ^ZAUTHENTICATE, you'll probably need to only have Delegated authentication checked/enabled for the service (this would of course mean the user is of type Delegated User instead of Cache Password User).

http://docs.intersystems.com/cache20152/csp/docbook/DocBook.UI.Page.cls?...

 

I need to perform additional check during Cache user authorization. Is there any way to do that?

If you're talking about having additional custom checks for a regular Cache Password user, I believe the answer is that it's not possible.  It would have to be a pure Delegated user to have additional checks (and the ZAUTHENTICATE routine would need to be completely responsible for the Delegated user's properties).

Hi,

I agree here, with Cache Password Authentication, once authenticated, there isn't any callback of way of extending the authentication with another step (further authentication). 

However - depending on your exact use case, you may use %ZSTART. All processes call into the routine %ZSTART at verious line labels (depending if they are a background job, interactive job, etc).  

see: http://docs.intersystems.com/cache20152/csp/docbook/DocBook.UI.Page.cls?...

 At the stage where you are in %ZSTART, you have already been authenticated - and perhaps, this is where you can craft something to achieve the end result that you are after.  It's worth looking into.

Steve

 

Two suggestions:

  1.  try returning a different error message.  One that might indicate an authentication error such as $SYSTEM.Status.Error($$$UserInvalidPassword).  I have not tried it myself, but this may work.  However, as someone else said this is really not the intended purpose of delegated authentication.  
  2. I am not sure about the nature of your additional checks.  However perhaps you can use the Login tag in %Zstart.

These are just suggestions as I have not had the chance to try either yet.

Tried both your suggestions, observed no change in authentication behaviour.

I stand somewhat corrected

do $System.Process.Terminate()

In %ZSTART(or ZAUTHENTICATE for that matter) does solve my problem. Seems like overkill, though. Really wanted just to return status.

Eduard,

It would help if there was further explanation of your use case. What is the "additional check" in question? Is it a flag on the user at the application level? Is it a call to some other system?

For simplicity, let's suppose your application has a role called TerminalUser that has the %Service_Console:U permission, and that it's the only role an application user might have that grants that permission.

If the "additional check" is based on a flag in your application, your application could simply add/remove the TerminalUser role when that flag changes. See class documentation for Security.* in the %SYS namespace. This might rely on a "privileged routine application" to escalate roles if the user changing this flag wouldn't normally have the necessary privileges to change security settings.

In either case, ZAUTHENTICATE might still work, although it wouldn't be as elegant. It could perform whatever additional checks are needed (against your application or some external system), and possibly add or remove the TerminalUser role based on the results. ZAUTHENTICATE would always return an error, so it falls back to password login. At that point the user could authenticate successfully but might not be allowed to use terminal if the TerminalUser role was removed. (I haven't tried this, but it seems like it could work.)

If you're using OS or Kerberos authentication, ZAUTHORIZE could also be relevant.

Additional check is calling external device to provide rfid/biometric/whatever authentication on the user logged in to provide additional security level. Yes, application approach seems to be better.

Exactly, what I want is two-factor authorisation but with my own authentication infrastructure for a second factor.

The title of the post is not quite correct. You would like to resolve something in the authentication step, not the authorization step. Please take a look at the ZAUTHENTICATE.mac in the SAMPLES namepace that includes a large array of options and code examples (most can be used just by uncommenting them). It also includes an example of performing 2 factor authentication. For this to work you have to validate the user's credientials first and then step into the 2 factor part of the authentication. Let me know if this helps. If not I will get you a more concrete implementaiton of ZAUTHENTICATE.

 

(Also please make sure that your authentication options for the service has the right list of options (in your case problably only delegate authentication))