By: Sean Kelly user 25 Aug 2020 at 9:29 a.m. CDT

16 Responses
Sean Kelly gravatar
How do I add Client Claims in the client_credentials flow?

By Michael Schwartz staff 25 Aug 2020 at 9:36 a.m. CDT

Michael Schwartz gravatar
Can you be more specific. What client claims do you want to add?

By Sean Kelly user 25 Aug 2020 at 9:39 a.m. CDT

Sean Kelly gravatar
I want to return some custom attributes as client claims.

By Michael Schwartz staff 25 Aug 2020 at 9:53 a.m. CDT

Michael Schwartz gravatar
Examples are helpful.

By Sean Kelly user 25 Aug 2020 at 9:56 a.m. CDT

Sean Kelly gravatar
I need to add a few alternative ID Guids to a client that are attached to the JWT when using the client credentials flow.

By Aliaksandr Samuseu staff 25 Aug 2020 at 10:21 a.m. CDT

Aliaksandr Samuseu gravatar
Hi, Sean. Normally, you won't get a JWT using client credentials flow. I assume you enabled access token as JWT feature? I believe you can use Introscpection custom scripts to add claims to this JWT in 4.x. Have you tried it already?

By Sean Kelly user 25 Aug 2020 at 10:29 a.m. CDT

Sean Kelly gravatar
Yes, I've had a go at using an introspection script. I was able to add claims with hardcoded values. I'm not to sure which class contains the values of the clients LDAP object. Are there any examples of using an introspection script to get these values?

By Michael Schwartz staff 25 Aug 2020 at 10:47 a.m. CDT

Michael Schwartz gravatar
I don't know what you mean by "alternative ID Guids". Do you intend to extend the `oxAuthClient` objectclass in Gluu, adding these custom attributes? For example, let's say you add an LDAP attribute called `myPartner` and then add this to the `oxAuthClient` objectclass. If so, in the introspection script: ``` from org.gluu.service.cdi.util import CdiUtil from org.gluu.oxauth.service import SessionIdService clientService = CdiUtil.bean(ClientService) CustomAttribute attribute = clientService.getCustomAttribute(client, "myPartner"); responseAsJsonObject.accumulate("key_from_scriptmyPartner", attribute.getValues()) ```

By Sean Kelly user 25 Aug 2020 at 5:25 p.m. CDT

Sean Kelly gravatar
Awesome! Thank you! I gave that a go with the following code but I'm getting this error. ``` # oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. # Copyright (c) 2018, Gluu # # Author: Yuriy Zabrovarnyy # # from org.gluu.model.custom.script.type.introspection import IntrospectionType from org.gluu.service.cdi.util import CdiUtil from org.gluu.oxauth.service import SessionIdService from java.lang import String class Introspection(IntrospectionType): def __init__(self, currentTimeMillis): self.currentTimeMillis = currentTimeMillis def init(self, configurationAttributes): print "Introspection script. Initializing ..." print "Introspection script. Initialized successfully" return True def destroy(self, configurationAttributes): print "Introspection script. Destroying ..." print "Introspection script. Destroyed successfully" return True def getApiVersion(self): return 1 # Returns boolean, true - apply introspection method, false - ignore it. # This method is called after introspection response is ready. This method can modify introspection response. # Note : # responseAsJsonObject - is org.codehaus.jettison.json.JSONObject, you can use any method to manipulate json # context is reference of org.gluu.oxauth.service.external.context.ExternalIntrospectionContext (in https://github.com/GluuFederation/oxauth project, ) def modifyResponse(self, responseAsJsonObject, context): clientService = CdiUtil.bean(ClientService) CustomAttribute attribute = clientService.getCustomAttribute(client, "givenName"); responseAsJsonObject.accumulate("key_from_scriptmyPartner", attribute.getValues()) return True ``` Traceback (most recent call last): File "introspection_sample.py", line 35, in modifyResponse NameError: global name 'getUser' is not defined at org.python.core.Py.NameError(Py.java:290) at org.python.core.PyFrame.getglobal(PyFrame.java:265) at org.python.pycode._pyx86.modifyResponse$6(introspection_sample.py:36) at org.python.pycode._pyx86.call_function(introspection_sample.py) at org.python.core.PyTableCode.call(PyTableCode.java:171) at org.python.core.PyBaseCode.call(PyBaseCode.java:308) at org.python.core.PyBaseCode.call(PyBaseCode.java:199) at org.python.core.PyFunction.__call__(PyFunction.java:482) at org.python.core.PyMethod.instancemethod___call__(PyMethod.java:237) at org.python.core.PyMethod.__call__(PyMethod.java:228) at org.python.core.PyMethod.__call__(PyMethod.java:218) at org.python.core.PyMethod.__call__(PyMethod.java:213) at org.python.core.PyObject._jcallexc(PyObject.java:3644) at org.python.core.PyObject._jcall(PyObject.java:3676) at org.python.proxies.__builtin__$Introspection$86.modifyResponse(Unknown Source) at org.gluu.oxauth.service.external.ExternalIntrospectionService.executeExternalModifyResponse(ExternalIntrospectionService.java:56) at org.gluu.oxauth.service.external.ExternalIntrospectionService.executeExternalModifyResponse(ExternalIntrospectionService.java:40) at org.gluu.oxauth.service.external.ExternalIntrospectionService$Proxy$_$$_WeldClientProxy.executeExternalModifyResponse(Unknown Source) at org.gluu.oxauth.model.common.AuthorizationGrant.runIntrospectionScriptAndInjectValuesIntoJwt(AuthorizationGrant.java:222) at org.gluu.oxauth.model.common.AuthorizationGrant.createAccessTokenAsJwt(AuthorizationGrant.java:211) at org.gluu.oxauth.model.common.AuthorizationGrant.createAccessToken(AuthorizationGrant.java:174) at org.gluu.oxauth.token.ws.rs.TokenRestWebServiceImpl.requestAccessToken(TokenRestWebServiceImpl.java:279) at org.gluu.oxauth.token.ws.rs.TokenRestWebServiceImpl$Proxy$_$$_WeldClientProxy.requestAccessToken(Unknown Source) at sun.reflect.GeneratedMethodAccessor842.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:140) at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:510) at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:401) at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$0(ResourceMethodInvoker.java:365) at org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:361) at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:367) at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:339) at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:312) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:441) at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:231) at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:137) at org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:361) at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:140) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:217) at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:227) at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56) at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51) at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:755) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1617) at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:226) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1604) at org.gluu.server.filters.AbstractCorsFilter.handleNonCORS(AbstractCorsFilter.java:362) at org.gluu.server.filters.AbstractCorsFilter.doFilter(AbstractCorsFilter.java:139) at org.gluu.oxauth.filter.CorsFilter.doFilter(CorsFilter.java:110) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1604) at org.gluu.oxauth.audit.debug.ServletLoggingFilter.doFilter(ServletLoggingFilter.java:67) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1596) at org.gluu.oxauth.auth.AuthenticationFilter.processBasicAuth(AuthenticationFilter.java:283) at org.gluu.oxauth.auth.AuthenticationFilter.doFilter(AuthenticationFilter.java:123) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1604) at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:545) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:590) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235) at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1607) at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233) at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1297) at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188) at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:485) at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1577) at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186) at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1212) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:221) at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:146) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) at org.eclipse.jetty.server.Server.handle(Server.java:500) at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:383) at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:547) at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:375) at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:270) at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129) at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:388) at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:806) at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:938) at java.lang.Thread.run(Thread.java:748)

By Michael Schwartz staff 26 Aug 2020 at 10:50 a.m. CDT

Michael Schwartz gravatar
To write these custom scripts, you need to be good at remote debugging. Or you need to add a bunch of print statements to get better feedback on where the script is failing. The snippet I provided above is a hint, not a recipe. If you need help writing this script, we have partners who can help you. Or you need to get VIP support. It's beyond the scope of community support.

By Sean Kelly user 29 Aug 2020 at 4:41 p.m. CDT

Sean Kelly gravatar
Thanks Michael! Where can I download the packages used in the example script so that I can play with them in Eclipse? ``` from org.gluu.model.custom.script.type.introspection import IntrospectionType from org.gluu.oxauth.service import SessionIdService from org.gluu.service.cdi.util import CdiUtil ```

By Michael Schwartz staff 29 Aug 2020 at 4:50 p.m. CDT

Michael Schwartz gravatar
See [https://gluu.org/docs/gluu-server/4.2/developer-guide/script-debugging/](https://gluu.org/docs/gluu-server/4.2/developer-guide/script-debugging/)

By Sean Kelly user 29 Aug 2020 at 4:53 p.m. CDT

Sean Kelly gravatar
Awesome! Thank you. By the way, there looks like there is broken link on that page. https://repo.gluu.org/tools/tools-install.sh There does exist a tools-intall-4.1.sh

By Sean Kelly user 29 Aug 2020 at 4:56 p.m. CDT

Sean Kelly gravatar
By the way, is there a Windows friendly way to get the packages? Are the jar files published somewhere?

By Sean Kelly user 29 Aug 2020 at 7:14 p.m. CDT

Sean Kelly gravatar
In this bit: ``` clientService = CdiUtil.bean(ClientService) CustomAttribute attribute = clientService.getCustomAttribute(client, "givenName"); ``` You are using an object called client. Where does this object come from?

By Sean Kelly user 29 Aug 2020 at 9:05 p.m. CDT

Sean Kelly gravatar
Solved it. For my requirement, I need to add a claim to the JWT with the value of a ID that relates to the calling system. I've added the value into the Software Identifier field on the Client and then used this script to have it returned in the JWT. ``` from org.gluu.model.custom.script.type.introspection import IntrospectionType from java.lang import String class Introspection(IntrospectionType): def __init__(self, currentTimeMillis): self.currentTimeMillis = currentTimeMillis def init(self, configurationAttributes): print "Introspection script. Initializing ..." print "Introspection script. Initialized successfully" return True def destroy(self, configurationAttributes): print "Introspection script. Destroying ..." print "Introspection script. Destroyed successfully" return True def getApiVersion(self): return 1 def modifyResponse(self, responseAsJsonObject, context): responseAsJsonObject.accumulate("software_id", context.getTokenGrant().getClient().getSoftwareId()) return True ``` Here’s a link to the object you get back from context.getTokenGrant().getClient(). https://github.com/GluuFederation/oxAuth/blob/master/common/src/main/java/org/gluu/oxauth/model/registration/Client.java Interestingly, this object seems to be missing the Client Description field. Is this field hiding under another property name?

By Michael Schwartz staff 30 Aug 2020 at 3:48 p.m. CDT

Michael Schwartz gravatar
Bravo!