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

Test helpers #8

Open
tombakerjr opened this issue May 22, 2017 · 17 comments
Open

Test helpers #8

tombakerjr opened this issue May 22, 2017 · 17 comments

Comments

@tombakerjr
Copy link

Hi there!

Do you have plans to add any test helpers to allow accessing authenticated routes in acceptance tests? In Ember Simple Auth, they provide a mechanism that lets you call authenticate directly with the token information, allowing you to "authenticate" and carry on with the test. It would be great if Ember Keycloak Auth could offer similar functionality. In lieu of that, do you have any workaround for "authenticating" in a test environment?

Cheers, and thanks for the great addon!

@sbflynn
Copy link
Contributor

sbflynn commented May 25, 2017

Hi Tom

No I hadn't - but now you mention it I think I probably should. I'm a bit tied up right now but will try to make a bit of time out to check out Ember Simple Auth and see how it was done there. Will keep you posted (and obviously any other thoughts you might have are more than welcome).

thanks, and best rgds,

Steve F.

@jufan
Copy link

jufan commented Jun 10, 2017

Hi team:
There is an issue on login redirect url.
Repro:

  1. Create ember new project.
  2. Add route: help.
  3. In the routes/application.js, init keycloak, but set it as "session.set('onLoad', 'check-sso');", allow user not logged in at home page.
  4. Update routes/help.js, add KeycloakAuthenticatedRouteMixin to require user login.

Note: At this point, it looks works. When open http://www.sample.com:4200/help, it redirect to keycloak login page and a user is able to log in.

Issue was start at:

when I update the environment.js, set as follows:
rootURL: '/test',
locationType: 'hash',

When open the site like www.sample.com:4200/test/#/help, it redirects to keycloak login page. But the keycloak login page return error: "Invalid parameter: redirect_uri".

The failure was caused by the redirect URL was set as: http://www.sample.com:4200#help.
It is wrong, the correct one should be http://www.sample.com:4200/test/#/help. The rootURL was missing.

Please help to take look and fix the issue. Thanks.

@rockyfaninus
Copy link

Oops, above comment should be in a new issue. Please ignore the previous comment. I create a new issue for it.

@lolmaus
Copy link

lolmaus commented Mar 1, 2019

We're converting our app to Keycloak and have tried this Ember addon. It worked out of the box!

But all our tests are a mess.

We need a way to mock authentication.

@sbflynn I can work on this. Do you have any specific approach in mind or should I come up with something on my own?

@Robin481
Copy link

Any Updates on this?

@lolmaus
Copy link

lolmaus commented May 23, 2019

I've ended up making a stub of the Keycloak service.

It mimics all the original methods so that it can be used in the app normally.

And it also has a simple auth store. You can erase the token and the app should gracefully log out next time it attempts using the token.

I can make a PR but I would like to validate the approach with addon maintainers before I spend time on it.

@Robin481
Copy link

@lolmaus That sounds great. Do you have this Stub in a Git Repository so I might have a look at it?
Looking forward to updates on this and I hope that this can be merged soon.

@Robin481
Copy link

Robin481 commented May 24, 2019

Alright I've figured it out myself, I just literally stubbed every method and every variable that the session uses. From what I can tell so far updateToken() is the only function that needs a little bit more magic than just an empty function.

keycloak-stub.js

import Service from '@ember/service';

export default Service.extend({
  tokenParsed: '1234',
  given_name: 'Name',
  token: '1234',
  roles: 'bla',
  keycloak: Object.freeze([{ token: '1234' }]),

  get headers() {},

  hasResourceRole(resource, role) {},

  installKeycloak(parameters) {},

  initKeycloak() {},

  hasRealmRole(role) {},

  _parseRedirectUrl(router, transition) {},

  loadUserProfile() {},

  login(redirectUri) {},

  logout(redirectUri) {},

  checkTransition(transition) {},

  updateToken() {
    return new Promise((resolve, reject) => { resolve() })
  }
})

And then imported it

import keycloakStub from '../helpers/keycloak-stub';

and added it in my acceptance test module beforeEach() function like this:

this.owner.register('service:keycloak-session', keycloakStub);

Keep in mind this does not really authenticate the user, it just bypasses all the functions. It's a good enough workaround for the Mixins in Acceptance tests atm.

@sbflynn
Copy link
Contributor

sbflynn commented May 24, 2019

@lolmaus
Stub makes sense - a PR would be great - otherwise I will do add something like @Robin481 when I get the time.

@lolmaus, @Robin481
I'm working on a prospective 0.4.x at the moment - looking to move the baseline support up to Ember LTS 3.8 - native classes, Stage 1 decorators, RouterService API, and using the new RouteMetadata API as an alternative to the current route mixin (mixins are a pet hate of mine).

Rough plan is a future 1.0 is going to be 'Octane' aligned.

As a quick straw poll - what versions of Ember are you focussed on ? Any thoughts welcome.

@Robin481
Copy link

Robin481 commented May 24, 2019

@sbflynn Thanks for answering!
Our Project is still stuck on Ember 3.0.4 ... but obviously we're looking to upgrade sooner or later, we just didn't get the time yet. Using a LTS Version of Ember seems reasonable to me.
The only thing I hope for is an easy and well-documented upgrade path, especially if moving away from mixins.

@sbflynn
Copy link
Contributor

sbflynn commented May 26, 2019

@Robin481

I have taken a first go at this - in the addon-test-support folder there is now a MockKeycloakSessionService class and a MockKeycloak class. The service mock extends the 'real' KeycloakSessionService class - it overrides a single method (installKeycloak()) to install a mock Keycloak Adapter instead of a 'real' Keycloak Adapter instance. The mock service can then be used in tests in exactly the way you suggested (example usage the add-on tests).

The bad news is that at the moment that only works for the latest (Ember 3.8+) version - it still needs to be back ported to earlier versions.

BTW the upgrade path, when you get there, should be straight forward as the service methods and the mixins remain unchanged. The latest version now deprecates the route mixin in favour of using the new RouteInfo Metadata API to trigger token update checks - but the route mixin will work just fine unchanged.

@Robin481
Copy link

@sbflynn Very cool, thanks a lot for your effort.
We're looking to update to Ember 3.8 some time soon. I'll give you an update when we get there and upgrade this package.

@lolmaus
Copy link

lolmaus commented May 29, 2019

Looks like I'm late for the party. 😔

In my implementation, I defined a simple token store:

export const AUTH_TOKEN = 'The most important thing is listening the recording of the music. It makes them gain a musical sense and gets to the point of the fast progress.'; // just a random string

interface AuthStore {
  token: string | null;
  authenticate(token?: string): void;
  invalidate(): void;
}

export const AUTH_STORE: AuthStore = {
  token: null,

  authenticate(token = AUTH_TOKEN) {
    this.token = token;
  },

  invalidate() {
    this.token = null;
  }
};

It's used in a mock service:

export class KeycloakSessionStubService extends Service {
  @service
  router!: RouterService;

  get authenticated() {
    return !!this.token;
  }

  get token() {
    // @ts-ignore
    return AUTH_STORE.token;
  }

  async checkTransition() {
    if (!this.authenticated) {
      return this.router.transitionTo('unauthenticated');
    } else {
      return;
    }
  }

  installKeycloak() {}
  initKeycloak() {}
  async updateToken() {}

  isStub = true;
}

And we use this to register the mock:

export default function setupKeycloackStub(hooks: TestHooks) {
  hooks.beforeEach( function() {
    this.owner.register('service:keycloak-session', KeycloakSessionStubService);
    assert('Keycloak-session service registration failed! Called the hook too late?', this.owner.lookup('service:keycloak-session').isStub);

    AUTH_STORE.invalidate();
  });
}

We also hack into Mirage so that it passes the token with every request. Our backend does not have public endpoints, so we don't need to check for authorization in every route handler.

import { AUTH_TOKEN } from './setup-keycloak-stub';
import { assert } from '@ember/debug';
import RouteHandler from 'ember-cli-mirage/route-handler';

export default function setupMirageAuth(hooks) {
  hooks.beforeEach(function() {
    this.__originalMirageRouteHandlerHandle__ = RouteHandler.prototype.handle;

    RouteHandler.prototype.handle = function(request) {
      assert('Unauthorized request', request.requestHeaders.authorization === `Bearer ${AUTH_TOKEN}`);

      return this
        ._getMirageResponseForRequest(request)
        .then((mirageResponse) => this.serialize(mirageResponse, request))
        .then((serializedMirageResponse) => serializedMirageResponse.toRackResponse());
    };

  });

  hooks.afterEach(function() {
    RouteHandler.prototype.handle = this.__originalMirageRouteHandlerHandle__;
    delete this.__originalMirageRouteHandlerHandle__;
  });
}

Note how the same token is used both in Mirage and in the mock service. The mock keeps functioning, checking for a valid token for every request. But it has all the Keycloak complexity removed.

In tests, I can do AUTH_STORE.authenticate() to put a valid or invalid token into the store and AUTH_STORE.invalidate() to remove it. It's a synchronous operation which would affect next network request.

This lets me test basic situations without delving into how Keycloak actually works.

@sbflynn What do you think? And is there any documentation/guidelines for your implementation?

@sbflynn
Copy link
Contributor

sbflynn commented May 29, 2019

@lolmaus

Not too late at all - party hardly started 🙂

I like your mirage setup and the shared token - definitely should add these in some form or other. I think that the token should be structured more like a real auth2 response so as to better test the addon itself.

I have, so far, stubbed the wrapped keycloak adapter rather than the service - so as to make tests a realistic as possible.

Always need better docs !

Best rgds

Steve F.

@lolmaus
Copy link

lolmaus commented May 31, 2019

Woah, just noticed the changes in the addon-test-support folder. S#@t's got serious! 🙀

@lolmaus
Copy link

lolmaus commented May 31, 2019

Note that now the addon is depending on Mirage, which might not be desirable for every app.

I think it would be OK if Mirage imports were moved to a separate file.

@sbflynn
Copy link
Contributor

sbflynn commented May 31, 2019

Good catch - I think you are right about separating the mirage stuff from the rest - should do the trick - will play with it later today.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants