OpenMRS and SSO

openldap
sso
Tags: #<Tag:0x00007f23de793bd8> #<Tag:0x00007f23de793a98>

(Ellen Ball) #1

Does anyone have experience implementing an SSO (single sign-on) scheme with OpenLDAP and OpenMRS?

Ellen Ball Partners In Health


(Robby O'Connor) #2

:+1: for making ID Dashboard this tool :smile: – though no clue how it will look :slight_smile:


(Michael Downey) #3

I think @ball is asking how to leverage SSO to authenticate to OpenMRS via a 3rd party user directory that an implementation is running. (Is that correct?)

When I see SSO, I think of the actual authentication happening in a other 3rd party application. OpenLDAP normally serves as simply a data source for an authentication app; it has no user friendly web UI. Alternatively @ball are you rather asking if you can just point OpenMRS at LDAP and do authentication within OpenMRS itself with LDAP’s IDs and passwords?


(Ellen Ball) #4

Yes, Michael. I am asking for colleagues working in Rwanda.


(Michael Downey) #5

Do you know if they have an existing OpenLDAP (or other) directory that they’re using for other systems, or would this be something new?


(Burke Mamlin) #6

TRUNK-381 has only been waiting five years for development. :wink:


(Robby O'Connor) #7

Isn’t the ultimate trajectory that ID Dashboard is heading to be the authentication scheme for OpenMRS as a whole – including the EMR System?


(Michael Downey) #8

No plans for that.


(Ellen Ball) #9

They wanted to use OpenLDAP for OpenMRS and OpenClinic SSO. OpenClinic appears to be popular in Rwanda for billing.

Hopefully my Rwanda colleagues will join OpenMRS Talk. We’re a friendly bunch.

Ellen


(Dimitri R) #10

@burke we are almost ready to submit a PR for TRUNK- 381 and I have a couple of last min design questions.

About the comments below:

/*
 * Authentication schemes define their own credentials.
 * Any client authenticating against a given scheme must
 * supply appropriate credentials.
 */
public interface Credentials {
  /*
   * Credentials will contains scheme-specific properties, but
   * all credentials must declare their scheme.
   */
  public String getAuthenticationScheme();
}

As a general matter of fact, isn’t it possible that a given implementation of Credentials (say a UserPassCredentials implementation) could be used to authenticate by multiple different schemes?

But let’s assume that each scheme works with one specific credentials implementation, then do we really need to expose which one through some string? At the end of the day a cast will be needed and failures to cast will point to unfit credentials for the scheme. See this example with a user-pass basic scheme:

public class UserPassAuthenticationScheme implements AuthenticationScheme {
  
  @Override
  public Authenticated authenticate(Credentials credentials)
      throws ContextAuthenticationException {
    
    UserPassCredentials userPassCreds = null;
    try {
      userPassCreds = (UserPassCredentials) credentials;
    }
    catch (ClassCastException e) {
      throw new ContextAuthenticationException(e);
    }
    
    return new Authenticated( Context.getContextDAO().authenticate(userPassCreds.getUsername(), userPassCreds.getPassword()) );
  }
}

Cc @amine


(Burke Mamlin) #11

Sure, it’s possible; however, it adds complexity. The problem we were trying to solve was the ability to define new schemes that weren’t all username & password-based and we were less concerned with being able to re-use Credentials for multiple schemes. And, more importantly, since we envisioned someone might come along and create an authenticate scheme that accepts username & password or tokens and then, depending on the credentials sent, forwards them to the correct authentication scheme, we didn’t want any ambiguity of which scheme should be used for a set of credentials.

It’s a fair point. I think the intent was for the case of someone coming along and wanting to support a couple different authentication schemes. Rather than building a mechanism to properly handle n schemes, we left it to the developer to solve the problem – i.e., given a username/password scheme and a token-based scheme, you could write a third scheme that takes username/password or token and then passes the credentials on to the appropriate scheme. In that model, the Credentials.getAuthenticationScheme() could be used as the discriminator to explicitly determine which scheme to be called without having to resort to inferences from introspection of the credentials.


(Dimitri R) #12

Thanks @burke. So @amine and I tried to keep the spirit of the suggested architecture as much as we could.

We’ll come up with a PR hopefully today or maybe tomorrow, it would be great if you could help review. I’ll make sure that you get hooked on GitHub. Just doing a few more tests at runtime both 1) in the default Platform/Ref App environment and 2) in another environment with a proof-of-concept module that delegates the authentication to Keycloak.

Cc @lilian


(Dimitri R) #13

@burke also right now Context.authenticate(String username, String password) does not return anything. I guess that was intentional, do you remember why?

If that was not intentional, should we aim for the new method to return Authenticated? As in:

/**
 * Authenticate user within the context with the provided authentication scheme and credentials.
 * 
 * @param The authentication scheme to use
 * @param The credentials to use to authenticate
 * @return The authenticated client information
 * @throws ContextAuthenticationException
 * 
 * @since 2.3.0
 */
public static Authenticated authenticate(AuthenticationScheme authenticationScheme, Credentials credentials) throws ContextAuthenticationException {
  ...
  return getUserContext().authenticate(authenticationScheme, credentials);
}