WebApp + Konnect with LDAP Backend



  • Ok,

    I have this code in my scope.yaml which should enable the scope:

    scopes:
      kopano/gc:
        description: "Read and write your Kopano Groupware data"
    

    but both kopano-core and my debuging service are not getting the scope in response. Is there additional configuration needed?


  • Kopano

    @alindemann said in WebApp + Konnect with LDAP Backend:

    but both kopano-core and my debuging service are not getting the scope in response. Is there additional configuration needed?

    Not that i can think of.

    When Konnect is started, it tells about the scopes getting loaded like this (debug logging enabled):

    registered scope                              id=kopano/gc priority=0
    

    Make sure you see a line like that. If you see that, and if you include the kopano/gc scope in the authorization endpoint request, please share further details of the requests you are sending. In the access token, you will be finding the scopes which got granted by Konnect.

    "kc.authorizedScopes": [
        "openid",
        "profile",
        "email",
        "kopano/gc"
      ],
    

    alternatively if you send prompt=consent or use an untrusted client, you will also see the scope in the consent screen.



  • Ok, I found a typo in the config (kopano/gc vs konnect/gc), fixed that and now the error message disappears.

    But I still can’t log in, following log lines appear:

    time="2019-07-16T13:30:10Z" level=debug msg="ldap identifier backend logon" id="uid=admin,<redacted>" username=admin
    time="2019-07-16T13:30:10Z" level=debug msg="identifier client lookup" client_id=kopano-webapp known=true redirect_uri="https://webmail.<redacted>/#oidc-callback " trusted=true
    time="2019-07-16T13:30:10Z" level=debug msg="identifier client lookup" client_id=kopano-webapp known=true redirect_uri="https://webmail.<redacted>/#oidc-callback " trusted=true
    Jul 16 13:30:11 kopano-32-l4rbr kopano-server[32]: Authentication by plugin failed for user "uid=admin,<redacted>": Trying to authenticate failed: uid=admin,<redacted> not found in LDAP; username = uid=admin,<redacted>
    Jul 16 13:30:11 kopano-32-l4rbr kopano-server[32]: Authentication by plugin failed for user "uid=admin,<redacted>": Trying to authenticate failed: uid=admin,<redacted> not found in LDAP; username = uid=admin,<redacted>
    

    Any thoughts about that ?


  • Kopano

    @alindemann said in WebApp + Konnect with LDAP Backend:

    Any thoughts about that ?

    Well i am unsure how this is supposed to work at the moment. You are using konnect directly with LDAP and then expect the kopano server to somehow map the user from LDAP to a Kopano user. I think this is currently not possible since the kopano-server expects the subject to be something it can understand (an ABEID) so it can map the user using its users table to the external user.

    Doing this the other way around might be possible, assuming some logic is added to the server’s access token validation/parsing which can allow the server to lookup the user using the external id directly. Needs work in provider/libserver/ECSession.cpp.

    What is your reason to set up Konnect with the LDAP backend instead of the kc backend?



  • Like said before, I want to have a solution I can use with other services, regardless whether there is a kopano server active in the specific setup. At the moment, it looks like I have to use the ldap backend if no kopano-server is present and the kc backend otherwise (with all implications to the other services).

    If I understand correctly, the kopano-server needs a specific sub format. So if I use another OIDC provider with custom configuration it could work with that? Could you hint me to some documentation or the source lines where the ABEID is handled?


  • Kopano

    @alindemann

    Understood and i guess it makes sense to consider this as a supported scenario in a future release. The code where the kopano server finds the correct user from the result of the token validation is at

    https://stash.kopano.io/projects/KC/repos/kopanocore/browse/provider/libserver/ECSession.cpp?until=f6d13f34fefe2181060b8a46c11aefaca6acfb58&untilPath=provider%2Flibserver%2FECSession.cpp#979-1007 - it should not be too hard to adapt. And figure out the extern ID from the access token.



  • Ok, thank you very much for your help, I have a working setup now with Keycloak as OIDC provider.


  • Kopano

    Hi @alindemann,

    would you mind sharing how you achieved your setup?



  • I used a oidc connector with one custom scope:

    {
        "name": "kopano/gc",
        "description": "Kopano Scope",
        "protocol": "openid-connect",
        "attributes": {
          "include.in.token.scope": "true",
          "display.on.consent.screen": "true"
        },
        "protocolMappers": [
          {
            "name": "kc.i.us",
            "protocol": "openid-connect",
            "protocolMapper": "oidc-script-based-protocol-mapper",
            "consentRequired": false,
            "config": {
              "userinfo.token.claim": "true",
              "id.token.claim": "true",
              "access.token.claim": "true",
              "claim.name": "kc\\.identity.kc\\.i\\.us",
              "jsonType.label": "String",
              "script": "/**\n * Available variables: \n * user - the current user\n * realm - the current realm\n * token - the current token\n * userSession - the current userSession\n * keycloakSession - the current userSession\n */\n\n\n//insert your code here...\n\nvar Base64 = Java.type(\"java.util.Base64\");\nvar encoder = Base64.getEncoder().withoutPadding();\n\nvar uid = user.getAttribute(\"LDAP_ID\")[0]\n\nexports = encoder.encodeToString(uid.getBytes())"
            }
          },
          {
            "name": "kc.provider",
            "protocol": "openid-connect",
            "protocolMapper": "oidc-hardcoded-claim-mapper",
            "consentRequired": false,
            "config": {
              "claim.value": "identifier-kc",
              "userinfo.token.claim": "true",
              "id.token.claim": "true",
              "access.token.claim": "true",
              "claim.name": "kc\\.provider",
              "jsonType.label": "String"
            }
          },
          {
            "name": "kc.authorizedScopes",
            "protocol": "openid-connect",
            "protocolMapper": "oidc-script-based-protocol-mapper",
            "consentRequired": false,
            "config": {
              "multivalued": "true",
              "userinfo.token.claim": "true",
              "id.token.claim": "true",
              "access.token.claim": "true",
              "claim.name": "kc\\.authorizedScopes",
              "script": "/**\n * Available variables: \n * user - the current user\n * realm - the current realm\n * token - the current token\n * userSession - the current userSession\n * keycloakSession - the current userSession\n */\n\n\n//insert your code here...\nvar ArrayList = Java.type(\"java.util.ArrayList\");\nvar scopes = new ArrayList();\n\nscopes.add(\"email\")\nscopes.add(\"openid\")\nscopes.add(\"profile\")\nscopes.add(\"kopano/gc\")\n\nexports = scopes"
            }
          },
          {
            "name": "kc.i.dn",
            "protocol": "openid-connect",
            "protocolMapper": "oidc-usermodel-attribute-mapper",
            "consentRequired": false,
            "config": {
              "userinfo.token.claim": "true",
              "user.attribute": "LDAP_ENTRY_NAME",
              "id.token.claim": "true",
              "access.token.claim": "true",
              "claim.name": "kc\\.identity.kc\\.i\\.dn",
              "jsonType.label": "String"
            }
          },
          {
            "name": "kc.isAccessToken",
            "protocol": "openid-connect",
            "protocolMapper": "oidc-hardcoded-claim-mapper",
            "consentRequired": false,
            "config": {
              "claim.value": "true",
              "userinfo.token.claim": "false",
              "id.token.claim": "false",
              "access.token.claim": "true",
              "claim.name": "kc\\.isAccessToken",
              "jsonType.label": "boolean"
            }
          },
          {
            "name": "kc.i.un",
            "protocol": "openid-connect",
            "protocolMapper": "oidc-usermodel-attribute-mapper",
            "consentRequired": false,
            "config": {
              "userinfo.token.claim": "true",
              "user.attribute": "LDAP_UID",
              "id.token.claim": "true",
              "access.token.claim": "true",
              "claim.name": "kc\\.identity.kc\\.i\\.un",
              "jsonType.label": "String"
            }
          },
          {
            "name": "kc.i.id",
            "protocol": "openid-connect",
            "protocolMapper": "oidc-script-based-protocol-mapper",
            "consentRequired": false,
            "config": {
              "userinfo.token.claim": "true",
              "id.token.claim": "true",
              "access.token.claim": "true",
              "claim.name": "kc\\.identity.kc\\.i\\.id",
              "jsonType.label": "String",
              "script": "/**\n * Available variables: \n * user - the current user\n * realm - the current realm\n * token - the current token\n * userSession - the current userSession\n * keycloakSession - the current userSession\n */\n\n\n//insert your code here...\nvar Base64 = Java.type(\"java.util.Base64\");\nvar encoder = Base64.getEncoder();\nvar uid = user.getAttribute(\"LDAP_ID\")[0]\n\nvar exid = encoder.encode(uid.getBytes())\n\nvar ByteOrder = Java.type(\"java.nio.ByteOrder\");\nvar ByteBuffer = Java.type(\"java.nio.ByteBuffer\");\n\nvar len = 32 + exid.length +4\n\nvar buffer = ByteBuffer.allocate(len).order(ByteOrder.LITTLE_ENDIAN)\n\n\n// abFlags[4]\nbuffer.putInt(0)\n\n//muidecsab\nbuffer.putInt(0x50a921ac)\nbuffer.putShort(0xd340)\nbuffer.putShort(0x48ee)\nbuffer.put(0xb3)\nbuffer.put(0x19)\nbuffer.put(0xfb)\nbuffer.put(0xa7)\nbuffer.put(0x53)\nbuffer.put(0x30)\nbuffer.put(0x44)\nbuffer.put(0x25)\n\n//ulVersion\nbuffer.putInt(0x1)\n//usType\nbuffer.putInt(0x6)\n//ulID (stub, uses extID)\nbuffer.putInt(0)\n\n//exID\nbuffer.put(exid)\n\nexports = encoder.encodeToString(buffer.array())"
            }
          }
        ]
      }
    

    the tricky attribute kc.i.id is being generated from a script (as seen above) which contains the following code in nice formatting:

    /**
     * Available variables: 
     * user - the current user
     * realm - the current realm
     * token - the current token
     * userSession - the current userSession
     * keycloakSession - the current userSession
     */
    
    
    //insert your code here...
    var Base64 = Java.type("java.util.Base64");
    var encoder = Base64.getEncoder();
    var uid = user.getAttribute("LDAP_ID")[0]
    
    var exid = encoder.encode(uid.getBytes())
    
    var ByteOrder = Java.type("java.nio.ByteOrder");
    var ByteBuffer = Java.type("java.nio.ByteBuffer");
    
    var len = 32 + exid.length +4
    
    var buffer = ByteBuffer.allocate(len).order(ByteOrder.LITTLE_ENDIAN)
    
    
    // abFlags[4]
    buffer.putInt(0)
    
    //muidecsab
    buffer.putInt(0x50a921ac)
    buffer.putShort(0xd340)
    buffer.putShort(0x48ee)
    buffer.put(0xb3)
    buffer.put(0x19)
    buffer.put(0xfb)
    buffer.put(0xa7)
    buffer.put(0x53)
    buffer.put(0x30)
    buffer.put(0x44)
    buffer.put(0x25)
    
    //ulVersion
    buffer.putInt(0x1)
    //usType
    buffer.putInt(0x6)
    //ulID (stub, uses extID)
    buffer.putInt(0)
    
    //exID
    buffer.put(exid)
    
    exports = encoder.encodeToString(buffer.array())
    

  • Kopano

    @alindemann so you haven’t used Konnect at all?


Log in to reply