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

Unable to use Gitlab OIDC provider - OpenIDConnectStrategy requires an authorizationURL option #4545

Closed
Poulpatine opened this issue Sep 12, 2022 · 9 comments · Fixed by #5856
Labels

Comments

@Poulpatine
Copy link

Poulpatine commented Sep 12, 2022

Describe the bug
I'm trying to use a self hosted Gitlab instance as OIDC auth provider and I'm facing the following error:

MeshCentral HTTP redirection server running on port 81.
MeshCentral v1.0.85, LAN mode, Production mode.
MeshCentral HTTP server running on port 80, alias port 443.
ERR: /opt/meshcentral/meshcentral/node_modules/@mstrhakr/passport-openidconnect/lib/strategy.js:32
  if (!options.authorizationURL) { throw new TypeError('OpenIDConnectStrategy requires an authorizationURL option'); }
                                         ^

TypeError: OpenIDConnectStrategy requires an authorizationURL option
    at new Strategy (/opt/meshcentral/meshcentral/node_modules/@mstrhakr/passport-openidconnect/lib/strategy.js:32:42)
    at /opt/meshcentral/meshcentral/webserver.js:7036:51
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
Error: Command failed: /usr/bin/node /opt/meshcentral/meshcentral/meshcentral --configfile config.json --launch 7
/opt/meshcentral/meshcentral/node_modules/@mstrhakr/passport-openidconnect/lib/strategy.js:32
  if (!options.authorizationURL) { throw new TypeError('OpenIDConnectStrategy requires an authorizationURL option'); }
                                         ^

TypeError: OpenIDConnectStrategy requires an authorizationURL option
    at new Strategy (/opt/meshcentral/meshcentral/node_modules/@mstrhakr/passport-openidconnect/lib/strategy.js:32:42)
    at /opt/meshcentral/meshcentral/webserver.js:7036:51
    at processTicksAndRejections (node:internal/process/task_queues:96:5)

    at ChildProcess.exithandler (node:child_process:398:12)
    at ChildProcess.emit (node:events:539:35)
    at maybeClose (node:internal/child_process:1092:16)
    at Socket.<anonymous> (node:internal/child_process:451:11)
    at Socket.emit (node:events:527:28)
    at Pipe.<anonymous> (node:net:709:12) {
  code: 1,
  killed: false,
  signal: null,
  cmd: '/usr/bin/node /opt/meshcentral/meshcentral/meshcentral --configfile config.json --launch 7'

Expected behavior
I want to authenticate using OIDC with my Gitlab instance as provider.

Screenshots
If applicable, add screenshots to help explain your problem.

Server Software (please complete the following information):

  • OS: Debian 11
  • Virtualization: Docker 20.10.17
  • Network: Traefik as reverse proxy
  • Version: v1.0.85
  • Node: v16.16.0 provided in Docker image

Client Device (please complete the following information):

  • Device: Laptop
  • OS: Arch
  • Network: Local to Meshcentral
  • Browser: Firefox
  • MeshCentralRouter Version: v1.0.85

Additional context
Add any other context about the problem here.

Your config.json file

{
  "$schema": "http://info.meshcentral.com/downloads/meshcentral-config-schema.json",
  "settings": {
    "plugins":{"enabled": false},
    "mongoDb": "mongodb://mongodbadmin:mysecretpassword@mongodb:27017",
    "WANonly": false,
    "LANonly": true,
    "sessionKey": "mysecretsessionkey",
    "port": 80,
    "redirPort": 81,
    "aliasPort": 443,
    "AgentPong": 300,
    "TLSOffload": true,
    "SelfUpdate": false,
    "AllowFraming": false,
    "WebRTC": false
  },
  "domains": {
    "": {
      "title": "MeshCentral",
      "title2": ".mysecretdomain.org",
      "minify": true,
      "NewAccounts": true,
      "orphanAgentUser": "removed@mysecretdomain.org",
      "localSessionRecording": false,
      "userNameIsEmail": true,
      "authStrategies": {
        "oidc": {
          "authorizationURL": "https://gitlab.mysecretdomain.org/oauth/authorize",
          "callbackURL": "https://meshcentral.mysecretdomain.org/oidc-callback",
          "clientid": "myclientid",
          "clientsecret": "mysecretclientsecret",
          "issuer": "https://gitlab.mysecretdomain.org:443",
          "tokenURL": "https://gitlab.mysecretdomain.org/oauth/token",
          "userInfoURL": "https://gitlab.mysecretdomain.org/oauth/userinfo",
          "logoutURL": "https://gitlab.mysecretdomain.org/oauth/revoke",
          "newAccounts": true
        }
      }
    }
  }
}

Edit:
BTW, here is the openid configuration provided by gitlab:

{
  "issuer": "https://gitlab.com",
  "authorization_endpoint": "https://gitlab.com/oauth/authorize",
  "token_endpoint": "https://gitlab.com/oauth/token",
  "revocation_endpoint": "https://gitlab.com/oauth/revoke",
  "introspection_endpoint": "https://gitlab.com/oauth/introspect",
  "userinfo_endpoint": "https://gitlab.com/oauth/userinfo",
  "jwks_uri": "https://gitlab.com/oauth/discovery/keys",
  "scopes_supported": [
    "api",
    "read_api",
    "read_user",
    "read_repository",
    "write_repository",
    "read_registry",
    "write_registry",
    "sudo",
    "openid",
    "profile",
    "email"
  ],
  "response_types_supported": [
    "code"
  ],
  "response_modes_supported": [
    "query",
    "fragment"
  ],
  "grant_types_supported": [
    "authorization_code",
    "password",
    "client_credentials",
    "refresh_token"
  ],
  "token_endpoint_auth_methods_supported": [
    "client_secret_basic",
    "client_secret_post"
  ],
  "subject_types_supported": [
    "public"
  ],
  "id_token_signing_alg_values_supported": [
    "RS256"
  ],
  "claim_types_supported": [
    "normal"
  ],
  "claims_supported": [
    "iss",
    "sub",
    "aud",
    "exp",
    "iat",
    "sub_legacy",
    "name",
    "nickname",
    "email",
    "email_verified",
    "website",
    "profile",
    "picture",
    "groups",
    "groups_direct",
    "https://gitlab.org/claims/groups/owner",
    "https://gitlab.org/claims/groups/maintainer",
    "https://gitlab.org/claims/groups/developer"
  ]
}
@Poulpatine Poulpatine added the bug label Sep 12, 2022
@mstrhakr
Copy link
Contributor

It should be using your manually defined value there, however, you should be able to use discovery by removing the authorization, token, and userInfo URLs.
This has not been updated in the docs yet.

Also you usually don't need the port number in the issuer field, when I was building this the first time, my reverse proxy was causing issues forcing me to add the port for it to work. Now you should not need or want the port number in there.

Updated config:

{
  "$schema": "http://info.meshcentral.com/downloads/meshcentral-config-schema.json",
  "settings": {
    "plugins":{"enabled": false},
    "mongoDb": "mongodb://mongodbadmin:mysecretpassword@mongodb:27017",
    "WANonly": false,
    "LANonly": true,
    "sessionKey": "mysecretsessionkey",
    "port": 80,
    "redirPort": 81,
    "aliasPort": 443,
    "AgentPong": 300,
    "TLSOffload": true,
    "SelfUpdate": false,
    "AllowFraming": false,
    "WebRTC": false
  },
  "domains": {
    "": {
      "title": "MeshCentral",
      "title2": ".mysecretdomain.org",
      "minify": true,
      "NewAccounts": true,
      "orphanAgentUser": "removed@mysecretdomain.org",
      "localSessionRecording": false,
      "userNameIsEmail": true,
      "authStrategies": {
        "oidc": {
          "callbackURL": "https://meshcentral.mysecretdomain.org/oidc-callback",
          "clientid": "myclientid",
          "clientsecret": "mysecretclientsecret",
          "issuer": "https://gitlab.mysecretdomain.org",
          "logoutURL": "https://gitlab.mysecretdomain.org/oauth/revoke",
          "newAccounts": true
        }
      }
    }
  }
}

@Poulpatine
Copy link
Author

Great, now I'm able to login with OIDC provided by Gitlab.

But, is it normal that meshcentral has no informations about my login (or email) even if email scope is available ?

Moreover, as described in Gitlab documentation , profile (and maybe email ?) scope should not be needed as openid scope already provides the required informations.

I've not yet tested the groups feature but it seems to be similar.

Whatever, thanks for the good work and for your help :).

@mstrhakr
Copy link
Contributor

mstrhakr commented Sep 14, 2022

Great, now I'm able to login with OIDC provided by Gitlab.

Hooray 🎉

But, is it normal that meshcentral has no informations about my login (or email) even if email scope is available ?

No. However it's possible GitLab has an email field in your profile that hasn't been filled out, the email scope doesn't grab from the email you use to login in most cases.

Moreover, as described in Gitlab documentation , profile (and maybe email ?) scope should not be needed as openid scope already provides the required informations.

From what I understand of OpenID Connect, the openid scope is meant for authentication only, not authorization, and does not provide any user details, hence further scopes such as profile, email, or groups are required to get those details.

With that said, if I've learned anything doing this, it's that everyone has their own way of doing things. So it's possible GitLab sends those details regardless. It's also possible that in addition to the basic OpenID Connect scopes, GitLab requires some additional scopes, or for the data to be pulled from an API endpoint using the token provided from the openid authentication.

I've not yet tested the groups feature but it seems to be similar.

At a glance of the documentation, you might be able to get away with just adding the groups section. Although if mesh isn't seeing your email there might be other issues getting groups also.

Whatever, thanks for the good work and for your help :).

Happy to help :)

Please ping me if you have any other issues with OpenID Connect on MeshCentral!

EDIT: GitLab OpenID Connect Docs

@Poulpatine
Copy link
Author

No. However it's possible GitLab has an email field in your profile that hasn't been filled out, the email scope doesn't grab from the email you use to login in most cases.

Yet my email is correctly registered in Gitlab.

At a glance of the documentation, you might be able to get away with just adding the groups section. Although if mesh isn't seeing your email there might be other issues getting groups also.
I've tried to enable groups but as "groups" scope is not available in Gitlab, I face an error

An error has occurred

The requested scope is invalid, unknown, or malformed.

I can do more tests if you want.

Thanks.

@mstrhakr
Copy link
Contributor

mstrhakr commented Sep 15, 2022

It looks like it should work, but only without adding the groups scope, which at that point we would need a custom config to parse groups and such correctly for GitLab instances.

Here's the GitLab documentation regarding OpenID Connect scopes:

openid Grants permission to authenticate with GitLab using OpenID Connect. Also gives read-only access to the user’s profile and group memberships.
profile Grants read-only access to the user’s profile data using OpenID Connect.
email Grants read-only access to the user’s primary email address using OpenID Connect.

The groups scope is not listed on that page, hence your error when we try to add it.

Here in the documentation they mention that the groups_direct CLAIM is included with the openid SCOPE (CAPITALS BECAUSE I KEEP MIXING THESE UP LOL):

The claims sub, sub_legacy, email, email_verified and groups_direct are included in the ID token. All other claims are available from the /oauth/userinfo endpoint used by OIDC clients.

This all seems to imply the info is there and in theory should be accessable to MeshCentral already, at least for you user info like email and name. The groups present an issue as groups_direct is a custom claim, and that requires me to make a custom profile for GitLab for it to work.

I'm rebuilding the OpenID Connect section at the moment so I'll add a GitLab preset to handle all that while I'm at it, but that won't be ready for weeks and I'm not sure how to help you now without you just using the branch I'm working on once I get a GitLab preset ready.

I'm still not sure why it's not taking in your email since that claim seems to be correct. So to that end, try adding "debug": "authlog" to the setting section of the config and you should see the full profile that is given by the current module.

@Poulpatine
Copy link
Author

Poulpatine commented Sep 16, 2022

I've made a few tests.

First, I've removed the line adding the "groups" in the scope array.
When I'm trying to login here are the logs I'm having:

AUTHLOG: OIDC: Connecting to https://gitlab.mysecretdomain.org with the following options {
    "issuer": "https://gitlab.mysecretdomain.org",
    "clientID": "myclientid",
    "clientSecret": "myclientsecret",
    "scope": [
        "openid",
        "profile",
        "email"
    ],
    "authorizationURL": "https://gitlab.mysecretdomain.org/oauth/authorize",
    "tokenURL": "https://gitlab.mysecretdomain.org/oauth/token",
    "userInfoURL": "https://gitlab.mysecretdomain.org/oauth/userinfo",
    "callbackURL": "https://meshcentral.mysecretdomain.org/oidc-callback"
}
AUTHLOG: oidc: Configured:
User: {
    "sid": "~oidc:111",
    "strategy": "oidc",
    "email": "username@secredomain.org"
}
FROM
Profile: {
    "id": "111",
    "emails": [
        {
            "value": "username@secredomain.org"
        }
    ]
}
AUTHLOG: OIDC: Verified user: {
    "sid": "~oidc:111",
    "strategy": "oidc",
    "email": "username@secredomain.org"
}{"sid":"~oidc:111","strategy":"oidc","email":"username@secredomain.org"}
AUTHLOG: OIDC: Member Of:
AUTHLOG: oidc: User login denied. User not found in required group.

Regarding the email field, it seems indeed to be found but unfortunately, the name is not:

AUTHLOG: oidc: Configured:
User: {
    "sid": "~oidc:111",
    "strategy": "oidc",
    "email": "username@mysecretdomain.org"
}
FROM
Profile: {
    "id": "111",
    "emails": [
        {
            "value": "username@mysecretdomain.org"
        }
    ]
}
AUTHLOG: OIDC: Verified user: {
    "sid": "~oidc:111",
    "strategy": "oidc",
    "email": "username@mysecretdomain.org"
}{"sid":"~oidc:111","strategy":"oidc","email":"username@mysecretdomain.org"}
AUTHLOG: OIDC: User Logged In: Name: null ID: user//~oidc:111

I've also figured out that the user list in Mesh Central seems to be messed up as once I've logged in with OIDC no users appears anymore in that list.

@mstrhakr
Copy link
Contributor

mstrhakr commented Sep 16, 2022

It's as I feared, even without that groups scope, the custom claim required by GitLab for groups isn't being read* by the passport module. It needs to be a bit more custom to grab those groups.

@mstrhakr
Copy link
Contributor

So this is partially a bug, if the user enables groups in 1.0.85, the groups scope is added regardless. So when we go to check if the group claim returned everything, it first checks to see if group scope was added, instead of checking that groups are enabled in the config. Its in webserver.js on line 7041

How it looks now

// Expanded single line for easier reading
if (options.scope.indexOf('groups') >= 0) {
  // If groups scope was used do this
  if ( Array.isArray(profile.groups[0].value) ) {
    // If groups claim value contains an array do this
    user.groups = profile.groups[0].value;
  } else {
    // Else do this
    user.groups = [profile.groups[0].value];
  }
}

How it should look

// Expanded single line for easier reading
if (typeof domain.authstrategies.oidc.groups == 'object') {
  // If groups are configured do this
  if ( Array.isArray(profile.groups[0].value) ) {
    // If groups claim value is an array do this
    user.groups = profile.groups[0].value;
  } else if ( typeof profile.groups[0].value == 'string') {
    // If groups claim value is a string do this
    user.groups = [profile.groups[0].value];
  } else {
    // Else do this
    user.groups = [];
  }
}

This would allow you to get your groups, if GitLab didn't use groups_direct as its primary group claim. Because the module we use right now doesn't support that custom claim, it can't return anything to the groups object in MeshCentral, even when the information is seemingly available.

I'm just about finished migrating this from the current OIDC node module to node-openid-client which should allow for much greater flexibility in general. In this new version of OIDC, coming soon(tm), I made some options that would allow you to set a custom group scope and claim, as well as adjust the name, email and uuid claims as necessary.

Fixed by #4530

@Poulpatine
Copy link
Author

Poulpatine commented Sep 22, 2022 via email

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

Successfully merging a pull request may close this issue.

2 participants