Giter Site home page Giter Site logo

fredx87 / cypress-keycloak-commands Goto Github PK

View Code? Open in Web Editor NEW
68.0 68.0 30.0 790 KB

Cypress commands for login with Keycloak

License: MIT License

TypeScript 52.96% JavaScript 3.84% HTML 43.21%
auth cypress e2e keycloak login oauth openid testing

cypress-keycloak-commands's Issues

Cross-Domain still an issue

Keycloak works great with Angular apps. I have had zero success testing my app due to Cypress.io's restriction of cross-domains. In a nutshell, I can log in using Keycloak (domain 1), using this cypress-keycloak-command (or by writing the steps out in a custom command).

BUT I cannot then make a call to my Angular app (domain 2) either using cy.visit('/') or cy.request('http://myAngularAppURL').

Has anyone successfully tested their application with this type of setup using Cypress?

Is anything in Cypress Keycloak Commands that addresses this issue?

I have searched endlessly and no solution is available. I have tried sending the auth-bearer when I make the request to my application, but this doesn't appear to be enough for Keycloak to accept as isAccessAllowed() in my Angular AuthGuard.

What am I missing?

kcLogin no longer working since Chrome 94?

Our tests login via kcLogin, skipping the actual login screen. This worked fine in both Chrome, Firefox and Electon, right until the point we've upgraded to Chrome 94.

It looks like kcLogin still makes the correct rest calls, getting 200s, but the user isn't logged in anymore when the test opens the page.

image

It does still work fine in Firefox 91 and Electron 89.
Does anyone have an idea how to solve this issue?

Cypress.json:

{
  "env": {
    "url": "http://localhost:3097",
    "auth_base_url": "http://vasiam.test.paas.vasdc.be/auth",
    "auth_realm": "wzcmh",
    "auth_client_id": "ui"
  },
  ...
  "chromeWebSecurity": false,
 ...
}
```

Is the static user fixture a requirement?

Wouldn't it be sensible to allow environment variables to determine the user, as is common in a CI context?

This solution requires one to commit user credentials into git ๐Ÿ˜“

Add support for client-secret beside client-id

In some KC configurations the client-secret is also required.

The quick fix below adds the client-secret from the cypress environment configuration (auth_client_secret) as client-secret (client_secret) in the token-request.

Maybe this value should be optional and only added if defined.

Index: node_modules/cypress-keycloak-commands/dist/kc-login.js
===================================================================
--- node_modules/cypress-keycloak-commands/dist/kc-login.js	(date 1587028385032)
+++ node_modules/cypress-keycloak-commands/dist/kc-login.js	(date 1587028385032)
@@ -7,6 +7,7 @@
         var authBaseUrl = Cypress.env("auth_base_url");
         var realm = Cypress.env("auth_realm");
         var client_id = Cypress.env("auth_client_id");
+        var client_secret = Cypress.env("auth_client_secret");
         cy.request({
             url: authBaseUrl + "/realms/" + realm + "/protocol/openid-connect/auth",
             followRedirect: false,
@@ -41,6 +42,7 @@
                 url: authBaseUrl + "/realms/" + realm + "/protocol/openid-connect/token",
                 body: {
                     client_id: client_id,
+                    client_secret: client_secret,
                     redirect_uri: Cypress.config("baseUrl"),
                     code: code,
                     grant_type: "authorization_code"

mock session-iframe instead of changing the frontend for runtime

In the docs the problem with the session status iframe is mentioned.

Besides from changing the frontend only for testing it is also possible to just provide a fake response for the iframe:

        cy.intercept(`<yourKeycloakInstance>/login-status-iframe.html`,
            {body: '<html><body><script>window.addEventListener("message", 
             (event) => {event.source.postMessage(\'unchanged\', event.origin);}, false);</script></body></html>'});

(see https://openid.net/specs/openid-connect-session-1_0.html#RPiframe)

I'm currently using this to avoid changing the frontend config only for testing.
That could be one possible fix for issues like issue #23.

Happy to provide a PR if this is helpful.

How do I get otp_secret and otp_credential_id?

Hi, I'm trying to authenticate to my API which uses OTP to login, but I'm having a hard time figuring out where do i find the otp_secret and the otp_credential_id.

I'm not sure this would be the place to ask, it's more of a keycloak question, but since there is an example in the documentation I was hoping someone could give any kind of directions.

Thanks

fakeLogin is not working with cypress 12

cypress-keycloak-commands library is still using cy.sever() and cy.route() . These commands are deprecated in Cypress 12 version. the test cases fail with cypress 12.

the below code in file

    cy.server();

    cy.route(
      "post",
      `${authBaseUrl}/realms/${realm}/protocol/openid-connect/token`,
      token
    );

    cy.route(`${authBaseUrl}/realms/${realm}/account`, account);

should be replaced with the below in order to work:

    cy.intercept(
        {method: 'post', url: authBaseUrl + "/realms/" + realm + "/protocol/openid-connect/token"},
        token
    );
    cy.intercept({method: 'get', url: authBaseUrl + "/realms/" + realm + "/account"}, account);

Source: https://docs.cypress.io/guides/references/migration-guide

Token request not stubbed when running tests on production environment

Hi,

Thanks a lot for your lib. Using the kcFakeLogin , we have speeded up our test execution.

When I run the tests against a local running application (ng serve). It works like a charm. (See stubbing of the /token request)

image

But if I run the tests against the production runtime (build with ng build --prod), the token request is not stubbed.

image

image

I though it was related to the fact that Cypress cannot stub fetchrequest. See this issue.

The Cypress team recently added an experimental feature to allow fetch request stubbing. (see doc here) but it doesn't seem to change anything. My fetch request is still not stubbed.

Do you have any idea why it doesn't work?

Error: self signed certificate in certificate chain

I have a couple of projects running the tests in SauceLabs. They were working correctly for a long time, but from 04/29/2021 they start failing with the error:

Sauce Cypress Runner 5.9.1
Preparing npm environment

Installing packages: [email protected]
FetchError: request to https://registry.npmjs.org/cypress-keycloak-commands failed, reason: self signed certificate in certificate chain
at ClientRequest. (D:\sauce-cypress-runner\5.9.1\bundle\node_modules\npm\node_modules\node-fetch-npm\src\index.js:68:14)
at ClientRequest.emit (events.js:315:20)
at ClientRequest.EventEmitter.emit (domain.js:467:12)
at TLSSocket.socketErrorListener (_http_client.js:469:9)
at TLSSocket.emit (events.js:315:20)
at TLSSocket.EventEmitter.emit (domain.js:467:12)
at emitErrorNT (internal/streams/destroy.js:106:8)
at emitErrorCloseNT (internal/streams/destroy.js:74:3)
at processTicksAndRejections (internal/process/task_queues.js:80:21) {
type: 'system',
errno: 'SELF_SIGNED_CERT_IN_CHAIN',
code: 'SELF_SIGNED_CERT_IN_CHAIN'
}

Any idea what could be the problem?

PKCE support

Is it possible to login when you have PKCE enabled in your Keycloak client? https://oauth.net/2/pkce/

I have PKCE enabled and this gives errors when I try to login with this library. When I disable PKCE, the login works just fine. Am I doing something wrong or is it just not supported? If so, it would be nice if the documentation could be extended with the remark that PKCE is currently not supported. It would be even nicer if PKCE would be supported by the library.

error: kcLogin: no location in response headers

I've been trying ot get cypress-keycloak-commands running both with kcFakeLogin and kcLogin (have not had any success with either).

Trying to do a real login with kcLogin results in the following error:

TypeError: Failed to construct 'URL': Invalid URL
    at Object.getAuthCodeFromLocation (http://localhost:3000/__cypress/tests?p=cypress/support/index.js:327:15)

digging into the code, it's expecting to receive a response.headers["location"] from keycloak. However that does not exist in the response I get from my keycloak instance:

{
  "Request Body": "username=mark@*****.com&password=********",
  "Request Headers": {
    "Connection": "keep-alive",
    "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36",
    "accept": "*/*",
    "cookie": "KC_RESTART=******.platform-keycloak-1",
    "content-type": "application/x-www-form-urlencoded",
    "accept-encoding": "gzip, deflate",
    "content-length": 66
  },
  "Request URL": "https://sso.******.com/auth/realms/rogers/login-actions/authenticate?session_code=******&execution=7e758598-c100-441e-bc6d-b8afe5091585&client_id=react-admin&tab_id=3xiTIiDql64",
  "Response Body": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" class=\"login-pf\">\n\n<head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n    <meta name=\"robots\" content=\"noindex, nofollow\">\n\n            <meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"/>\n    <title>Log in to ****</title>\n    <link rel=\"icon\" href=\"/auth/resources/4.8.3.final/login/keycloak-theme-colony/img/favicon.ico\" />\n            <link href=\"/auth/resources/4.8.3.final/login/keycloak-theme-colony/css/styles.css\" rel=\"stylesheet\" />\n<SCRIPT> if (typeof history.replaceState === 'function') {  history.replaceState({}, \"some title\", \"https://sso.******.com/auth/realms/****/login-actions/authenticate?execution=7e758598-c100-441e-bc6d-b8afe5091585&client_id=react-admin&tab_id=3xiTIiDql64\"); }</SCRIPT></head>\n\n<body class=\"\">\n  <div class=\"login-pf-page\">\n    <div id=\"kc-header\" class=\"login-pf-page-header\">\n      <div id=\"kc-header-wrapper\" class=\"\">rogers</div>\n    </div>\n    <div class=\"card-pf login-pf-accounts\">\n      <header class=\"login-pf-header\">\n        <h1 id=\"kc-page-title\">        Log In\n\n</h1>\n      </header>\n      <div id=\"kc-content\">\n        <div id=\"kc-content-wrapper\">\n\n              <div class=\"alert alert-error\">\n                  \n                  \n                  <span class=\"pficon pficon-error-circle-o\"></span>\n                  \n                  <span class=\"kc-feedback-text\">Invalid username or password.</span>\n              </div>\n\n    <div id=\"kc-form\" class=\"row\">\n      <div id=\"kc-form-wrapper\" class=\"col-xs-12 col-sm-6 login-pf-social-section\">\n            <form id=\"kc-form-login\" onsubmit=\"login.disabled = true; return true;\" action=\"https://sso.*****.com/auth/realms/***/login-actions/authenticate?session_code=*****&amp;execution=7e758598-c100-441e-bc6d-b8afe5091585&amp;client_id=react-admin&amp;tab_id=3xiTIiDql64\" method=\"post\">\n                <div class=\"form-group\">\n                    <label for=\"username\" class=\"control-label\">Username or email</label>\n\n                        <input tabindex=\"1\" id=\"username\" class=\"form-control\" name=\"username\" value=\"mark@******.com\"  type=\"text\" autofocus autocomplete=\"off\" />\n                </div>\n\n                <div class=\"form-group\">\n                    <label for=\"password\" class=\"control-label\">Password</label>\n                    <input tabindex=\"2\" id=\"password\" class=\"form-control\" name=\"password\" type=\"password\" autocomplete=\"off\" />\n                </div>\n\n                <div class=\"form-group login-pf-settings\">\n                    <div id=\"kc-form-options\">\n                        </div>\n                        <div class=\"\">\n                        </div>\n\n                  </div>\n\n                  <div id=\"kc-form-buttons\" class=\"form-group\">\n                    <input tabindex=\"4\" class=\"btn btn-primary btn-block btn-lg\" name=\"login\" id=\"kc-login\" type=\"submit\" value=\"Log In\"/>\n                  </div>\n            </form>\n        </div>\n            <div id=\"kc-social-providers\" class=\"col-xs-12 col-sm-6 login-pf-social-section\">\n                <ul class=\"login-pf-social list-unstyled login-pf-social-all \">\n                        <li class=\"login-pf-social-link\"><a href=\"/auth/realms/****/broker/r4b/login?client_id=react-admin&amp;tab_id=3xiTIiDql64&amp;session_code=jhQzUBJy4bKmcRGtDuR9MtsWzJKY3XiGy0wNVPO7f7U\" id=\"zocial-r4b\" class=\"zocial saml\"> <span>******</span></a></li>\n                </ul>\n            </div>\n      </div>\n\n\n              <div id=\"kc-info\" class=\"login-pf-signup\">\n                  <div id=\"kc-info-wrapper\" class=\"\">\n\n                  </div>\n              </div>\n        </div>\n      </div>\n\n    </div>\n  </div>\n</body>\n</html>\n",
  "Response Headers": {
    "cache-control": "no-store, must-revalidate, max-age=0",
    "x-xss-protection": "1; mode=block",
    "x-frame-options": "SAMEORIGIN",
    "content-security-policy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';",
    "date": "Fri, 25 Sep 2020 22:00:13 GMT",
    "x-robots-tag": "none",
    "strict-transport-security": "max-age=31536000; includeSubDomains",
    "x-content-type-options": "nosniff",
    "content-type": "text/html;charset=utf-8",
    "content-length": "3946",
    "content-language": "en",
    "via": "1.1 google",
    "alt-svc": "clear"
  },
  "Response Status": 200
}

screenshot:
Screen Shot 2020-09-25 at 17 16 22

my initConfig:

{
        responseMode: 'fragment',
        flow: 'standard',
        onLoad: 'login-required',
        checkLoginIframe: false,
}

my users/user.json fixture:

{
  "username": "mark@******.com",
  "password": "*******",
  "fakeLogin": {
    "access_token": "********",
    "refreshToken": "********",
    "id_token": "********",
    "account": {
      "allowed_company_uids": "1",
      "aud": "account",
      "auth_time": 1601067578,
      "azp": "react-admin",
      "colony_admin_sections": "device_v3,wifi_service_v3,captive_portal_v3,site,probe,dns_service,company,SignalTest",
      "colony_available_products": "Sitehealth Failover,SecureBlock,Sitehealth Primary,Cloudfi,SignalTest",
      "colony_role": "api_user",
      "email": "mark@********.com",
      "email_verified": true,
      "exp": 1601068478,
      "family_name": "***",
      "given_name": "Mark",
      "iat": 1601067578,
      "iss": "https://sso.********.com/auth/realms/colony_internal",
      "jti": "2f590383-b4f3-4353-8ca3-689da65e8bd0",
      "name": "Mark ********",
      "nbf": 0,
      "nonce": "809a8adb-5b20-4326-8ecc-92c1190834ed",
      "preferred_username": "mark",
      "scope": "openid profile email",
      "session_state": "28088320-d761-4f2a-8a5a-d138f9e0c47a",
      "sub": "3f1af098-a974-4dac-af84-6262e506b330",
      "typ": "Bearer",
      "realm_access": {
        "roles": ["viewer", "editor", "offline_access", "admin", "uma_authorization", "user"]
      },
      "resource_access": {
        "account": {
          "roles": ["manage-account", "manage-account-links", "view-profile"]
        }
      }
    }
  }
}

I'm not sure why it's trying to read a location header or what that's for?

if I hardcode it to use http://localhost:3000 as the location it gets past this part just fine, but I then get a different 400 error:

Body: {
  "error": "unauthorized_client",
  "error_description": "Client secret not provided in request"
}

I normally pass a secret to keycloak, but that doesn't seem to be an option with this module?

Chrome 87, Cookies and kcLogin

I'm having an issue with cookies and CSP violations with Chrome Version 87.0, Keycloak 11.
Running the same tests in the election browser they work.

They also work when I set these flags to disabled in Chrome or Chrome Edge:

chrome://flags/#same-site-by-default-cookies
chrome://flags/#cookies-without-same-site-must-be-secure

I don't think its an issue with this plugin, just looking for advice if anyone noticed it and how they solved it.

kcFakeLogin stuck on redirecting

When trying to login with kcFakeLogin, cypress just gets infinitely stuck on page loading.

Screen Shot 2020-09-25 at 18 40 33

my users/user.json fixture:

{
  "username": "mark@*****.com",
  "password": "*****",
  "fakeLogin": {
    "access_token": "*****",
    "refreshToken": "*****",
    "id_token": "*****",
    "account": {}
  }
}

I've tripple checked the tokens and info above are correct (copied from a real login).

my test:

describe('Keycloak', () => {
  it('Keycloak loads', () => {
    cy.kcFakeLogin('user');
  });
});

initConfig:

{
        flow: 'implicit',
        onLoad: 'check-sso',
        checkLoginIframe: false,
}

(I have tried replacing this with the one from your docs, but that didn't work either).

cypress.json

{
  "baseUrl": "http://localhost:3000",
  "env": {
    "auth_base_url": "https://sso.****.com/auth",
    "auth_realm": "****",
    "auth_client_id": "react-admin",
    "auth_client_secret": "*****"
  }
}

my normal keycloak.json looks like this:

{
  "auth-server-url": "https://sso.*****.com/auth",
  "confidential-port": 0,
  "credentials": { "secret": "*****" },
  "realm": "rogers",
  "resource": "react-admin",
  "ssl-required": "external"
}

I'm not sure if there's anything special here that this npm module isn't built to handle?

Visiting localhost:3000 of course works just fine in the browser.

I've been trying to get this working for 5 hours today with no luck.

Cannot authenticate - No cookies being set

Hello, feeling stuck and wondering if anyone has clues. Here is my setup, from what I can tell it's pretty standard.

Front end is Create React App. I'm using this library to handle login and watch auth state:
https://www.npmjs.com/package/@react-keycloak/web

I have created a fixture with user credentials that work when I log in manually.

I call cy.kcLogin('me') but my app never makes it to a private route, it just bounces back to /login

If I run the following in a cypress test: cy.kcLogin('fixtureUsername').as('tokens') and use the returned tokens against my API, I get data back from a protected route, so kcLogin is doing what it should, at least it's getting valid tokens.

A teammate figured this had something to do with cookies not being set, thus the application doesn't detect that KC is logged in. I put a bunch of cy.getCookies() calls in my tests and sure enough there are never any cookies.

So then I tried preserving cookies in before(() => {})

  beforeEach(() => {
    cy.kcLogout()
    cy.kcLogin('me').as('tokens')
    Cypress.Cookies.preserveOnce(
      'KC_RESTART',
      'AUTH_SESSION_ID',
      'AUTH_SESSION_LEGACY',
      'KEYCLOAK_IDENTITY',
      'KEYCLOAK_IDENTITY_LEGACY',
      'KEYCLOAK_LOCALE',
      'KEYCLOAK_REMEMBER_ME'
    )
  })

but still no luck. I've also written a test that manually logs in:

  it('Logs in via keycloak', () => {
    cy.visit('/')
    cy.contains('Log In')
    cy.get('button').click()
    cy.url().should('include', 'auth/realms/court')
    cy.url().should('include', 'keycloak')
    cy.fixture('users/me.json').then(me => {
      cy.get(`input[name='username']`)
        .type(me.username)
      cy.get(`input[name='password']`)
        .type(me.password)
      cy.get(`input[name='login']`).click()
      cy.location('pathname').should('include', 'authenticate')
      cy.location('search').should('include', 'session_code=')
    })
  })

All of those tests pass, but I'm never sent back to my application, it just remains on a keycloak url at the end, wondering if that's a clue as maybe this is more to do with my setup than with cypress-keycloak-commands

Can provide more code if anyone wants to see anything else!

Here are my init options at this point, I've tried the variations on these:

    <KeycloakProvider
      authClient={keycloakClient}
      LoadingComponent={<Box p={2}><CircularProgress /></Box>}
      initOptions={{
        enableLogging: true,
        checkLoginIframe: false,
        silentCheckSsoFallback: false
      }}
    >

I'm authenticating to a 'public' client, btw, so no client secrets are in play.

cy.kcFakeLogin is not a function

Hello,
I am trying to implement the Fake Login for Integration testing
I am using angular 12 and cypress 4.4.1

I am done as described in the tutorial.

  • I have imported the line import "cypress-keycloak-commands"; in commands.ts and hence there is no error while using the commands in the vscode editor.
  • I have Setup the Keycloak configuration in cypress.json configuration file
  • i have added the user token detail in the fixture file cypress/fixtures/users/user.json

when i run my e2e test, I get the following error when my cypress tests run
cy.kcFakeLogin is not a function

Could you please help as I am stuck

kcLogin: Blocked a frame with origin "http://localhost:3000" from accessing a cross-origin frame.

after kcLogin finishes and its('body') is logged in Cypress (last step of kcLogin succeeds)

Cypress then navigates to / and then fails with the following error:

Refused to frame 'https://sso.xxxxx.com/' because an ancestor violates the following Content Security Policy directive: "frame-ancestors 'self'".

After some googling I tried setting "chromeWebSecurity": false, in cypress.json as recommended.

However doing that causes cypress to redirect to chrome-error://chromewebdata/ which there is a multi-year long discussion about here: cypress-io/cypress#4220

sadly this seems to have never been resolved.

There was 1 recommended solution "Using the Ignore X-Frame headers extension", which I tried, but that did not solve the problem for me.

I feel like I'm going down a rabbit hole for something completely unrelated, as no one else has reported the initial Iframe error on here?

I'm having the exact same error using kcFakeLogin.

Versions on the frontend:
"keycloak-js": "9.0.3",
"@react-keycloak/web": "^2.1.1",

Keycloak server:
Server Version | 4.8.3.Final

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.