├── .gitignore
├── README.md
├── pom.xml
└── src
└── main
├── java
└── CustomOIDCProtocolMapper.java
└── resources
└── META-INF
├── jboss-deployment-structure.xml
└── services
└── org.keycloak.protocol.ProtocolMapper
/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**
5 | !**/src/test/**
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 |
30 | ### VS Code ###
31 | .vscode/
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # KeycloakCustomProtocolMapper
2 |
3 | implement a CustomProtocolMapper class based on AbstractOIDCProtocolMapper
4 |
5 | META-INF/services File with the name org.keycloak.protocol.ProtocolMapper must be available and contains the name of mapper
6 |
7 | jboss-deployment-structure.xml need to be available to use keycloak built in classes
8 |
9 | Jar File is deployed in /opt/jboss/keycloak/standalone/deployments/
10 |
11 | custom Mapper
12 | use POM.xml and resolve dependencies
13 | Extend AbstractOIDCProtocolMapper and need to implement all abstract methods. If want to have a SAML Protocol Mapper then it's another base class (AbstractSAMLProtocolMapper)
14 | one relevant method is transformAccessToken -can implement logic here.
15 |
16 | Services File
17 | The services File is important for keycloak to find the custom-Implementation.
18 | Place a file with the fileName org.keycloak.protocol.ProtocolMapper inside \src\main\resources\META-INF\services\
19 |
20 | Inside this file write to Name of your custom Provider - then keycloak knows that this class is available as Protocol Mapper
21 | can add multiple file names
22 |
23 | CustomOIDCProtocolMapper
24 |
25 | Deployment Structure XML
26 | In custom mapper use files from keycloak. In order to use them it's needed to inform jboss about this dependency. Therefore create a file jboss-deployment-structure.xml inside \src\main\resources\META-INF\ Content:
27 |
28 | Build and deploy your Extension
29 | Build a jar File of the Extension (mvn clean package) - and place the jar in /opt/jboss/keycloak/standalone/deployments/ and restart keycloak
30 |
31 | create a Mapper in keycloak admin ui and select getDisplayType given in the code
32 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | net.cake.keycloak.custom
8 | keycloak-customProtocolMapper
9 | 1.0-SNAPSHOT
10 | jar
11 |
12 |
13 | 8.0.0
14 |
15 |
16 |
17 |
18 |
19 | org.keycloak
20 | keycloak-core
21 | ${keycloak.version}
22 | provided
23 |
24 |
25 | org.keycloak
26 | keycloak-server-spi
27 | ${keycloak.version}
28 | provided
29 |
30 |
31 | org.keycloak
32 | keycloak-server-spi-private
33 | ${keycloak.version}
34 | provided
35 |
36 |
37 | org.keycloak
38 | keycloak-services
39 | ${keycloak.version}
40 | provided
41 |
42 |
43 |
44 | org.keycloak
45 | keycloak-saml-core
46 | ${keycloak.version}
47 | provided
48 |
49 |
50 | org.keycloak
51 | keycloak-saml-adapter-core
52 | ${keycloak.version}
53 | provided
54 |
55 |
56 |
57 | org.keycloak
58 | keycloak-saml-adapter-api-public
59 | ${keycloak.version}
60 | provided
61 |
62 |
63 | org.keycloak
64 | keycloak-saml-core-public
65 | ${keycloak.version}
66 | provided
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | org.apache.maven.plugins
75 | maven-compiler-plugin
76 | 3.7.0
77 |
78 | true
79 | 1.8
80 | 1.8
81 |
82 |
83 |
84 | org.apache.maven.plugins
85 | maven-shade-plugin
86 | 3.1.0
87 |
88 |
89 |
90 | package
91 |
92 | shade
93 |
94 |
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/src/main/java/CustomOIDCProtocolMapper.java:
--------------------------------------------------------------------------------
1 | import org.keycloak.models.ClientSessionContext;
2 | import org.keycloak.models.KeycloakSession;
3 | import org.keycloak.models.ProtocolMapperModel;
4 | import org.keycloak.models.UserSessionModel;
5 | import org.keycloak.protocol.oidc.OIDCLoginProtocol;
6 | import org.keycloak.protocol.oidc.mappers.*;
7 | import org.keycloak.provider.ProviderConfigProperty;
8 | import org.keycloak.representations.AccessToken;
9 |
10 | import java.util.ArrayList;
11 | import java.util.HashMap;
12 | import java.util.List;
13 | import java.util.Map;
14 |
15 | public class CustomOIDCProtocolMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper {
16 |
17 | public static final String PROVIDER_ID = "oidc-customprotocolmapper";
18 |
19 | private static final List configProperties = new ArrayList();
20 |
21 | /**
22 | * Maybe you want to have config fields for your Mapper
23 | */
24 | /*
25 | static {
26 | ProviderConfigProperty property;
27 | property = new ProviderConfigProperty();
28 | property.setName(ProtocolMapperUtils.USER_ATTRIBUTE);
29 | property.setLabel(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_LABEL);
30 | property.setHelpText(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_HELP_TEXT);
31 | property.setType(ProviderConfigProperty.STRING_TYPE);
32 | configProperties.add(property);
33 |
34 | property = new ProviderConfigProperty();
35 | property.setName(ProtocolMapperUtils.MULTIVALUED);
36 | property.setLabel(ProtocolMapperUtils.MULTIVALUED_LABEL);
37 | property.setHelpText(ProtocolMapperUtils.MULTIVALUED_HELP_TEXT);
38 | property.setType(ProviderConfigProperty.BOOLEAN_TYPE);
39 | configProperties.add(property);
40 |
41 | }
42 | */
43 | @Override
44 | public List getConfigProperties() {
45 | return configProperties;
46 | }
47 |
48 | @Override
49 | public String getDisplayCategory() {
50 | return TOKEN_MAPPER_CATEGORY;
51 | }
52 |
53 | @Override
54 | public String getDisplayType() {
55 | return "ohhhhhh noooooooooooo";
56 | }
57 |
58 | @Override
59 | public String getId() {
60 | return PROVIDER_ID;
61 | }
62 |
63 | @Override
64 | public String getHelpText() {
65 | return "some help text";
66 | }
67 |
68 | // public IDToken transformAccessToken(IDToken token, ProtocolMapperModel mappingModel, KeycloakSession keycloakSession,
69 | // UserSessionModel userSession, ClientSessionContext clientSessionCtx) {
70 | ////IDToken token, ProtocolMapperModel mappingModel, UserSessionModel userSession, KeycloakSession keycloakSession, ClientSessionContext clientSessionCtx
71 | // token.getOtherClaims().put("stackoverflowCustomToken", "stackoverflow");
72 | //// token.getOtherClaims().
73 | // // call profile API and enrich with permission claims
74 | //// setClaim(token, mappingModel, userSession);
75 | // setClaim(token, mappingModel, userSession, keycloakSession,clientSessionCtx);
76 | // return token;
77 | // }
78 |
79 | public AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession keycloakSession,
80 | UserSessionModel userSession, ClientSessionContext clientSessionCtx) {
81 |
82 | token.getOtherClaims().put("supiri", "token_supiri");
83 |
84 | setClaim(token, mappingModel, userSession, keycloakSession, clientSessionCtx);
85 | return token;
86 | }
87 |
88 | // public static ProtocolMapperModel create(String name, boolean accessToken, boolean idToken, boolean userInfo) {
89 | // ProtocolMapperModel mapper = new ProtocolMapperModel();
90 | // mapper.setName(name);
91 | // mapper.setProtocolMapper(PROVIDER_ID);
92 | // mapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
93 | // Map config = new HashMap();
94 | // config.put("id.token.claim", "true");
95 | // config.put("access.token.claim", "true");
96 | // mapper.setConfig(config);
97 | // return mapper;
98 | // }
99 |
100 | public static ProtocolMapperModel create(String name,
101 | boolean accessToken, boolean idToken, boolean userInfo) {
102 | ProtocolMapperModel mapper = new ProtocolMapperModel();
103 | mapper.setName(name);
104 | mapper.setProtocolMapper(PROVIDER_ID);
105 | mapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
106 | Map config = new HashMap();
107 | // config.put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, hardcodedName);
108 | // config.put(CLAIM_VALUE, hardcodedValue);
109 | // config.put(OIDCAttributeMapperHelper.JSON_TYPE, claimType);
110 | config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
111 | config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true");
112 | mapper.setConfig(config);
113 | return mapper;
114 | }
115 |
116 | }
117 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/jboss-deployment-structure.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper:
--------------------------------------------------------------------------------
1 | CustomOIDCProtocolMapper
--------------------------------------------------------------------------------