Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TRUNK-381: Support for alternate authentication schemes #2833

Merged
merged 4 commits into from
Feb 18, 2019

Conversation

ahammi
Copy link
Contributor

@ahammi ahammi commented Feb 14, 2019

Issue I worked on

see https://issues.openmrs.org/browse/TRUNK-381

Checklist: I completed these to help reviewers :)

  • My pull request only contains ONE single commit
    (the number above, next to the 'Commits' tab is 1).

    No? -> read here on how to squash multiple commits into one

  • My IDE is configured to follow the code style of this project.

    No? Unsure? -> configure your IDE, format the code and add the changes with git add . && git commit --amend

  • I have added tests to cover my changes. (If you refactored
    existing code that was well tested you do not have to add tests)

    No? -> write tests and add them to this commit git add . && git commit --amend

  • I ran mvn clean package right before creating this pull request and
    added all formatting changes to my commit.

    No? -> execute above command

  • All new and existing tests passed.

    No? -> figure out why and add the fix to your commit. It is your responsibility to make sure your code works.

  • My pull request is based on the latest changes of the master branch.

    No? Unsure? -> execute command git pull --rebase upstream master

@coveralls
Copy link

coveralls commented Feb 14, 2019

Coverage Status

Coverage decreased (-0.06%) to 59.458% when pulling 35290cf on ahammi:TRUNK-381 into c9996a6 on openmrs:master.


/**
* A basic implementation of {@link Authenticated} that contains the necessary elements for an OpenMRS authentication.
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you put a since annotation on this class?

* Base class for authentication schemes that intend to leverage OpenMRS' {@link ContextDAO}.
*
* @see {@link Context#authenticate(AuthenticationScheme, Credentials)}
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you put a since annotation on this?

* Typically in the case of a user the client would simply be identified with its username.
*/
public String getClientName();

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you plan to deal with this? "Credentials will contains scheme-specific properties"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dkayiwa this quote comes from @bmamlin's suggested JavaDoc on the ticket's description. I think the point is that devs/implementers can keep extending Credentials implementations (such as extending UserPassCredentials for example) or can provide their own implementations of Credentials. Either way they will add members and methods that are useful to their custom auth. schemes. We can't anticipate as of yet what will be done, we can just leave the design open enough.

*/
public class UserPassAuthenticationScheme extends DaoAuthenticationScheme {

protected static Log log = LogFactory.getLog(UserPassAuthenticationScheme.class);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why the above is not private static final?

*/
public class UserPassCredentials implements Credentials {

protected String username;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why these are not private?

/*
* This test auth scheme logs a user simply based on asserting that its UUID is valid and points to an exisiting user.
*/
public class TestUuidAuthenticationScheme extends DaoAuthenticationScheme {
Copy link
Member

@dkayiwa dkayiwa Feb 15, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be better to instead of use a test with a username and password? Some sort of admin/test combination. For this to me looks closer to the real basic authentication which we have that is based on a username and password combination.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to say this more explicitly, this test should also stay to ensure that we support more than just our basic username and password db based authentication.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dkayiwa yes absolutely, this test should have existed already with the method that we suggest to deprecate. Anyway I added it in the commit #3.

public Authenticated authenticate(AuthenticationScheme authenticationScheme, Credentials credentials)
throws ContextAuthenticationException {

if (log.isDebugEnabled()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the log.isDebugEnabled() check?


return this.user;
if (log.isDebugEnabled()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the log.isDebugEnabled() check?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dkayiwa those checks are all over the code base though, so I will let them in for now. I agree that it's weird, I would have assumed that a logger knows whether it supports debugging or not. Please advise.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure there is any such in the latest version of master?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dkayiwa yes if you do a search, simply via GitHub like here, you will find dozens. One example on Concept: https://github.com/openmrs/openmrs-core/blob/master/api/src/main/java/org/openmrs/Concept.java#L451

Permalink here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was a pull request which removed those in a number of classes. I just noticed that it did not fully remove them from the entire codebase. 😊

public Authenticated authenticate(Credentials credentials)
throws ContextAuthenticationException {

if (log.isDebugEnabled()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the log.isDebugEnabled() check?

@dkayiwa
Copy link
Member

dkayiwa commented Feb 15, 2019

Which API will a module use for the wiring of a new authentication scheme? Will that be in another pull request?

@mks-d
Copy link
Member

mks-d commented Feb 15, 2019

Which API will a module use for the wiring of a new authentication scheme? Will that be in another pull request?

@dkayiwa no wiring per se, you just explicitly invoke Context.authenticate(AuthenticationScheme, Credentials) with your own pair scheme/credentials defined in your custom module.

We are working on a OAuth2 client module that authenticates with Keycloak, we will be able to provide an example shortly with a custom scheme. No Spring magic as of yet.

@mks-d mks-d changed the title TRUNK-381: Support for alternate authentication scheme TRUNK-381: Support for alternate authentication schemes Feb 15, 2019
@dkayiwa
Copy link
Member

dkayiwa commented Feb 16, 2019

@mks-d what i mean is when some one wants the existing unmodified openmrs reference application login page to use a custom authentication scheme provided by a module.

@@ -267,6 +267,9 @@ public static void setContext(ServiceContext ctx) {
}

/**
* @deprecated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dkayiwa I did this in my last commit:

/**
 * @deprecated as of 2.3.0, replaced by #authenticate(AuthenticationScheme, Credentials)
 ...
 */

Is that what you expect? If not please point me to the exact JavaDoc that you would like to have in place.

public Authenticated authenticate(Credentials credentials)
throws ContextAuthenticationException {

if (log.isDebugEnabled()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the log.isDebugEnabled() check?

@mks-d
Copy link
Member

mks-d commented Feb 18, 2019

@mks-d what i mean is when some one wants the existing unmodified openmrs reference application login page to use a custom authentication scheme provided by a module.

@dkayiwa this PR does not yet cover such use case. It rather provides devs with an API to authenticate with other schemes if they need to.

Btw I would suggest that we follow up with a PR on the Ref App module so that it uses the new API rather than the one that will be deprecated.

@dkayiwa
Copy link
Member

dkayiwa commented Feb 18, 2019

I was looking at this text in the ticket description: " Ideally, substitution (or addition) of the authentication scheme would be protected (e.g., limited to the configuration file setting or not easily done through the API) so that random code could not easily substitute a bogus authentication scheme to subvert proper authentication."

My understanding of the above was not to necessarily hard code the UsernamePasswordAuthenticationScheme but provide it as the default with ability to be overridden by the same authenticate(String username, String password) method call.

@dkayiwa
Copy link
Member

dkayiwa commented Feb 18, 2019

Infact the public authenticate(AuthenticationScheme authenticationScheme, Credentials credentials) seems to do the opposite of the above. That is, makes it so easy for some random code to substitute a bogus authentication scheme to subvert proper authentication. 😊

@mks-d
Copy link
Member

mks-d commented Feb 18, 2019

Infact the public authenticate(AuthenticationScheme authenticationScheme, Credentials credentials) seems to do the opposite of the above. That is, makes it so easy for some random code to substitute a bogus authentication scheme to subvert proper authentication. 😊

@dkayiwa I see, so authentication schemes should be Spring-wired, and the Spring config would use the add and remove protected methods. So that's how UserContext knows which scheme(s) to use.
But when using an alternate scheme, how does one pass to UserContext the credentials to use with the scheme, since the only method that could ever be called is Context.authenticate(String username, String password)?

Does that imply that the only user identification that could ever be passed downstream is the username?

@mks-d
Copy link
Member

mks-d commented Feb 18, 2019

@dkayiwa more precisely, deep down one will rely on ContextDAO to fetch the authenticated user, and it's only possible to fetch users by UUID (see here). What will be needed by alternate schemes is a getUserByUsername(String) so this will be added in the next commit.

@dkayiwa dkayiwa merged commit 1d76f10 into openmrs:master Feb 18, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants