keycloak-uncached

Changes

Details

diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
index 4313b7b..10e8988 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
@@ -201,6 +201,16 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
             throw new ErrorPageException(session, authenticationSession, Response.Status.FORBIDDEN, Messages.BEARER_ONLY);
         }
 
+        String protocol = client.getProtocol();
+        if (protocol == null) {
+            logger.warnf("Client '%s' doesn't have protocol set. Fallback to openid-connect. Please fix client configuration", clientId);
+            protocol = OIDCLoginProtocol.LOGIN_PROTOCOL;
+        }
+        if (!protocol.equals(OIDCLoginProtocol.LOGIN_PROTOCOL)) {
+            event.error(Errors.INVALID_CLIENT);
+            throw new ErrorPageException(session, authenticationSession, Response.Status.BAD_REQUEST, "Wrong client protocol.");
+        }
+
         session.getContext().setClient(client);
     }
 
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java
index 13520b7..03ff614 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java
@@ -218,7 +218,7 @@ public class LogoutEndpoint {
         ClientModel client = AuthorizeClientUtil.authorizeClient(session, event).getClient();
 
         if (client.isBearerOnly()) {
-            throw new ErrorResponseException("invalid_client", "Bearer-only not allowed", Response.Status.BAD_REQUEST);
+            throw new ErrorResponseException(Errors.INVALID_CLIENT, "Bearer-only not allowed", Response.Status.BAD_REQUEST);
         }
 
         return client;
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java
index 0e5e1e5..a486aa8 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java
@@ -41,6 +41,7 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.services.ErrorResponseException;
 import org.keycloak.services.Urls;
@@ -149,6 +150,11 @@ public class UserInfoEndpoint {
             throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Client not found", Response.Status.BAD_REQUEST);
         }
 
+	    if (!clientModel.getProtocol().equals(OIDCLoginProtocol.LOGIN_PROTOCOL)) {
+            event.error(Errors.INVALID_CLIENT);
+            throw new ErrorResponseException(Errors.INVALID_CLIENT, "Wrong client protocol.", Response.Status.BAD_REQUEST);
+        }
+
         session.getContext().setClient(clientModel);
 
         event.client(clientModel);
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java b/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java
index ffff19c..88720d1 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java
@@ -17,10 +17,12 @@
 
 package org.keycloak.protocol.oidc.utils;
 
+import org.jboss.logging.Logger;
 import org.jboss.resteasy.spi.HttpRequest;
 import org.keycloak.authentication.AuthenticationProcessor;
 import org.keycloak.authentication.ClientAuthenticator;
 import org.keycloak.authentication.ClientAuthenticatorFactory;
+import org.keycloak.events.Errors;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.models.AuthenticationFlowModel;
 import org.keycloak.models.ClientModel;
@@ -40,6 +42,8 @@ import java.util.Map;
  */
 public class AuthorizeClientUtil {
 
+    private static final Logger logger = Logger.getLogger(AuthorizeClientUtil.class);
+
     public static ClientAuthResult authorizeClient(KeycloakSession session, EventBuilder event) {
         AuthenticationProcessor processor = getAuthenticationProcessor(session, event);
 
@@ -50,7 +54,18 @@ public class AuthorizeClientUtil {
 
         ClientModel client = processor.getClient();
         if (client == null) {
-            throw new ErrorResponseException("invalid_client", "Client authentication ended, but client is null", Response.Status.BAD_REQUEST);
+            throw new ErrorResponseException(Errors.INVALID_CLIENT, "Client authentication ended, but client is null", Response.Status.BAD_REQUEST);
+        }
+
+        String protocol = client.getProtocol();
+        if (protocol == null) {
+            logger.warnf("Client '%s' doesn't have protocol set. Fallback to openid-connect. Please fix client configuration", client.getClientId());
+            protocol = OIDCLoginProtocol.LOGIN_PROTOCOL;
+        }
+
+        if (!protocol.equals(OIDCLoginProtocol.LOGIN_PROTOCOL)) {
+            event.error(Errors.INVALID_CLIENT);
+            throw new ErrorResponseException(Errors.INVALID_CLIENT, "Wrong client protocol.", Response.Status.BAD_REQUEST);
         }
 
         session.getContext().setClient(client);
diff --git a/services/src/main/java/org/keycloak/protocol/saml/SamlService.java b/services/src/main/java/org/keycloak/protocol/saml/SamlService.java
index b8a32f5..b78d519 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/SamlService.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/SamlService.java
@@ -175,6 +175,13 @@ public class SamlService extends AuthorizationEndpointBase {
                 event.error(Errors.CLIENT_NOT_FOUND);
                 return ErrorPage.error(session, null, Response.Status.BAD_REQUEST, Messages.CLIENT_NOT_FOUND);
             }
+
+            if (!isClientProtocolCorrect(client)) {
+                event.event(EventType.LOGOUT);
+                event.error(Errors.INVALID_CLIENT);
+                return ErrorPage.error(session, null, Response.Status.BAD_REQUEST, "Wrong client protocol.");
+            }
+
             session.getContext().setClient(client);
             logger.debug("logout response");
             Response response = authManager.browserLogout(session, realm, userSession, session.getContext().getUri(), clientConnection, headers);
@@ -225,6 +232,11 @@ public class SamlService extends AuthorizationEndpointBase {
                 event.error(Errors.NOT_ALLOWED);
                 return ErrorPage.error(session, null, Response.Status.BAD_REQUEST, Messages.STANDARD_FLOW_DISABLED);
             }
+            if (!isClientProtocolCorrect(client)) {
+                event.event(EventType.LOGIN);
+                event.error(Errors.INVALID_CLIENT);
+                return ErrorPage.error(session, null, Response.Status.BAD_REQUEST, "Wrong client protocol.");
+            }
 
             session.getContext().setClient(client);
 
@@ -607,6 +619,14 @@ public class SamlService extends AuthorizationEndpointBase {
           key.getKid(), PemUtils.encodeCertificate(key.getCertificate()), purpose, false));
     }
 
+    private boolean isClientProtocolCorrect(ClientModel clientModel) {
+        if (SamlProtocol.LOGIN_PROTOCOL.equals(clientModel.getProtocol())) {
+            return true;
+        }
+
+        return false;
+    }
+
     @GET
     @Path("clients/{client}")
     @Produces(MediaType.TEXT_HTML_UTF_8)
@@ -631,6 +651,10 @@ public class SamlService extends AuthorizationEndpointBase {
             event.error(Errors.CLIENT_DISABLED);
             return ErrorPage.error(session, null, Response.Status.BAD_REQUEST, Messages.CLIENT_DISABLED);
         }
+        if (!isClientProtocolCorrect(client)) {
+            event.error(Errors.INVALID_CLIENT);
+            return ErrorPage.error(session, null, Response.Status.BAD_REQUEST, "Wrong client protocol.");
+        }
         if (client.getManagementUrl() == null && client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_POST_ATTRIBUTE) == null && client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE) == null) {
             logger.error("SAML assertion consumer url not set up");
             event.error(Errors.INVALID_REDIRECT_URI);
diff --git a/services/src/main/java/org/keycloak/services/clientregistration/AbstractClientRegistrationProvider.java b/services/src/main/java/org/keycloak/services/clientregistration/AbstractClientRegistrationProvider.java
index bbd10a9..476e0dd 100755
--- a/services/src/main/java/org/keycloak/services/clientregistration/AbstractClientRegistrationProvider.java
+++ b/services/src/main/java/org/keycloak/services/clientregistration/AbstractClientRegistrationProvider.java
@@ -100,10 +100,9 @@ public abstract class AbstractClientRegistrationProvider implements ClientRegist
         }
     }
 
-    public ClientRepresentation get(String clientId) {
+    public ClientRepresentation get(ClientModel client) {
         event.event(EventType.CLIENT_INFO);
 
-        ClientModel client = session.getContext().getRealm().getClientByClientId(clientId);
         auth.requireView(client);
 
         ClientRepresentation rep = ModelToRepresentation.toRepresentation(client, session);
diff --git a/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationAuth.java b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationAuth.java
index 4e1a96f..447bb9d 100644
--- a/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationAuth.java
+++ b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationAuth.java
@@ -36,15 +36,13 @@ import org.keycloak.models.UserModel;
 import org.keycloak.protocol.oidc.utils.AuthorizeClientUtil;
 import org.keycloak.representations.JsonWebToken;
 import org.keycloak.services.ErrorResponseException;
-import org.keycloak.services.clientregistration.policy.RegistrationAuth;
 import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyException;
 import org.keycloak.services.clientregistration.policy.ClientRegistrationPolicyManager;
-import org.keycloak.services.managers.RealmManager;
+import org.keycloak.services.clientregistration.policy.RegistrationAuth;
 import org.keycloak.util.TokenUtil;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
 import java.util.List;
 import java.util.Map;
 
@@ -62,11 +60,13 @@ public class ClientRegistrationAuth {
     private ClientInitialAccessModel initialAccessModel;
     private String kid;
     private String token;
+    private String endpoint;
 
-    public ClientRegistrationAuth(KeycloakSession session, ClientRegistrationProvider provider, EventBuilder event) {
+    public ClientRegistrationAuth(KeycloakSession session, ClientRegistrationProvider provider, EventBuilder event, String endpoint) {
         this.session = session;
         this.provider = provider;
         this.event = event;
+        this.endpoint = endpoint;
     }
 
     private void init() {
@@ -129,6 +129,8 @@ public class ClientRegistrationAuth {
         RegistrationAuth registrationAuth = RegistrationAuth.ANONYMOUS;
 
         if (isBearerToken()) {
+            checkClientProtocol();
+
             if (hasRole(AdminRoles.MANAGE_CLIENTS, AdminRoles.CREATE_CLIENT)) {
                 registrationAuth = RegistrationAuth.AUTHENTICATED;
             } else {
@@ -162,6 +164,8 @@ public class ClientRegistrationAuth {
         init();
 
         if (isBearerToken()) {
+            checkClientProtocol();
+
             if (hasRole(AdminRoles.MANAGE_CLIENTS, AdminRoles.VIEW_CLIENTS)) {
                 if (client == null) {
                     throw notFound();
@@ -224,10 +228,26 @@ public class ClientRegistrationAuth {
         }
     }
 
+    private void checkClientProtocol() {
+        ClientModel client = session.getContext().getRealm().getClientByClientId(jwt.getIssuedFor());
+
+        checkClientProtocol(client);
+    }
+
+    private void checkClientProtocol(ClientModel client) {
+        if (endpoint.equals("openid-connect") || endpoint.equals("saml2-entity-descriptor")) {
+            if (client != null && !endpoint.contains(client.getProtocol())) {
+                throw new ErrorResponseException(Errors.INVALID_CLIENT, "Wrong client protocol.", Response.Status.BAD_REQUEST);
+            }
+        }
+    }
+
     private RegistrationAuth requireUpdateAuth(ClientModel client) {
         init();
 
         if (isBearerToken()) {
+            checkClientProtocol();
+
             if (hasRole(AdminRoles.MANAGE_CLIENTS)) {
                 if (client == null) {
                     throw notFound();
@@ -344,6 +364,8 @@ public class ClientRegistrationAuth {
             throw unauthorized("Different client authenticated");
         }
 
+        checkClientProtocol(authClient);
+
         return true;
     }
 
diff --git a/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationService.java b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationService.java
index 3345129..ed1a73b 100644
--- a/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationService.java
+++ b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationService.java
@@ -52,7 +52,7 @@ public class ClientRegistrationService {
         }
 
         provider.setEvent(event);
-        provider.setAuth(new ClientRegistrationAuth(session, provider, event));
+        provider.setAuth(new ClientRegistrationAuth(session, provider, event, providerId));
         return provider;
     }
 
diff --git a/services/src/main/java/org/keycloak/services/clientregistration/DefaultClientRegistrationProvider.java b/services/src/main/java/org/keycloak/services/clientregistration/DefaultClientRegistrationProvider.java
index 0b58145..de2a615 100755
--- a/services/src/main/java/org/keycloak/services/clientregistration/DefaultClientRegistrationProvider.java
+++ b/services/src/main/java/org/keycloak/services/clientregistration/DefaultClientRegistrationProvider.java
@@ -17,6 +17,7 @@
 
 package org.keycloak.services.clientregistration;
 
+import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.representations.idm.ClientRepresentation;
 
@@ -55,8 +56,9 @@ public class DefaultClientRegistrationProvider extends AbstractClientRegistratio
     @Path("{clientId}")
     @Produces(MediaType.APPLICATION_JSON)
     public Response getDefault(@PathParam("clientId") String clientId) {
-        ClientRepresentation client = get(clientId);
-        return Response.ok(client).build();
+        ClientModel client = session.getContext().getRealm().getClientByClientId(clientId);
+        ClientRepresentation clientRepresentation = get(client);
+        return Response.ok(clientRepresentation).build();
     }
 
     @PUT
diff --git a/services/src/main/java/org/keycloak/services/clientregistration/oidc/OIDCClientRegistrationProvider.java b/services/src/main/java/org/keycloak/services/clientregistration/oidc/OIDCClientRegistrationProvider.java
index 246d60e..d2a03a1 100755
--- a/services/src/main/java/org/keycloak/services/clientregistration/oidc/OIDCClientRegistrationProvider.java
+++ b/services/src/main/java/org/keycloak/services/clientregistration/oidc/OIDCClientRegistrationProvider.java
@@ -100,8 +100,11 @@ public class OIDCClientRegistrationProvider extends AbstractClientRegistrationPr
     @Path("{clientId}")
     @Produces(MediaType.APPLICATION_JSON)
     public Response getOIDC(@PathParam("clientId") String clientId) {
-        ClientRepresentation client = get(clientId);
-        OIDCClientRepresentation clientOIDC = DescriptionConverter.toExternalResponse(session, client, session.getContext().getUri().getRequestUri());
+        ClientModel client = session.getContext().getRealm().getClientByClientId(clientId);
+
+        ClientRepresentation clientRepresentation = get(client);
+
+        OIDCClientRepresentation clientOIDC = DescriptionConverter.toExternalResponse(session, clientRepresentation, session.getContext().getUri().getRequestUri());
         return Response.ok(clientOIDC).build();
     }
 
@@ -175,5 +178,4 @@ public class OIDCClientRegistrationProvider extends AbstractClientRegistrationPr
         }
         rep.setProtocolMappers(mappings);
     }
-
 }
diff --git a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
index e6001eb..5dd5056 100755
--- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
+++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
@@ -24,6 +24,7 @@ import org.keycloak.authentication.AuthenticationProcessor;
 import org.keycloak.authentication.authenticators.broker.AbstractIdpAuthenticator;
 import org.keycloak.authentication.authenticators.broker.util.PostBrokerLoginConstants;
 import org.keycloak.authentication.authenticators.broker.util.SerializedBrokeredIdentityContext;
+import org.keycloak.broker.oidc.KeycloakOIDCIdentityProviderFactory;
 import org.keycloak.broker.provider.AuthenticationRequest;
 import org.keycloak.broker.provider.BrokeredIdentityContext;
 import org.keycloak.broker.provider.IdentityBrokerException;
@@ -32,6 +33,7 @@ import org.keycloak.broker.provider.IdentityProviderFactory;
 import org.keycloak.broker.provider.IdentityProviderMapper;
 import org.keycloak.broker.provider.util.IdentityBrokerState;
 import org.keycloak.broker.saml.SAMLEndpoint;
+import org.keycloak.broker.saml.SAMLIdentityProviderFactory;
 import org.keycloak.broker.social.SocialIdentityProvider;
 import org.keycloak.common.ClientConnection;
 import org.keycloak.common.util.Base64Url;
@@ -70,6 +72,7 @@ import org.keycloak.representations.AccessToken;
 import org.keycloak.services.ErrorPage;
 import org.keycloak.services.ErrorPageException;
 import org.keycloak.services.ErrorResponse;
+import org.keycloak.services.ErrorResponseException;
 import org.keycloak.services.ServicesLogger;
 import org.keycloak.services.Urls;
 import org.keycloak.services.managers.AppAuthManager;
@@ -1240,7 +1243,6 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
         }
     }
 
-
     private static class ParsedCodeContext {
         private ClientSessionCode<AuthenticationSessionModel> clientSessionCode;
         private Response response;
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java
index 11b81e7..ff3e520 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java
@@ -21,10 +21,12 @@ package org.keycloak.testsuite.client;
 import org.junit.Before;
 import org.junit.Test;
 import org.keycloak.OAuth2Constants;
+import org.keycloak.admin.client.resource.ClientsResource;
 import org.keycloak.client.registration.Auth;
 import org.keycloak.client.registration.ClientRegistrationException;
 import org.keycloak.client.registration.HttpErrorException;
 import org.keycloak.common.util.CollectionUtil;
+import org.keycloak.events.Errors;
 import org.keycloak.jose.jws.Algorithm;
 import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
@@ -33,19 +35,19 @@ import org.keycloak.representations.idm.ClientInitialAccessCreatePresentation;
 import org.keycloak.representations.idm.ClientInitialAccessPresentation;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
 import org.keycloak.representations.oidc.OIDCClientRepresentation;
 import org.keycloak.testsuite.Assert;
 import org.keycloak.testsuite.admin.ApiUtil;
+import org.keycloak.testsuite.util.KeycloakModelUtils;
 
 import java.util.*;
 
-import javax.ws.rs.core.Response;
-
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -58,8 +60,14 @@ public class OIDCClientRegistrationTest extends AbstractClientRegistrationTest {
     @Override
     public void addTestRealms(List<RealmRepresentation> testRealms) {
         super.addTestRealms(testRealms);
-        testRealms.get(0).setPrivateKey(PRIVATE_KEY);
-        testRealms.get(0).setPublicKey(PUBLIC_KEY);
+        RealmRepresentation testRealm = testRealms.get(0);
+        testRealm.setPrivateKey(PRIVATE_KEY);
+        testRealm.setPublicKey(PUBLIC_KEY);
+
+        ClientRepresentation samlApp = KeycloakModelUtils.createClient(testRealm, "saml-client");
+        samlApp.setSecret("secret");
+        samlApp.setServiceAccountsEnabled(true);
+        samlApp.setDirectAccessGrantsEnabled(true);
     }
 
     @Before
@@ -103,6 +111,19 @@ public class OIDCClientRegistrationTest extends AbstractClientRegistrationTest {
         }
     }
 
+    private void assertGetFail(String clientId, int expectedStatusCode, String expectedErrorContains) {
+        try {
+            reg.oidc().get(clientId);
+            Assert.fail("Not expected to successfully get client");
+        } catch (ClientRegistrationException expected) {
+            HttpErrorException httpEx = (HttpErrorException) expected.getCause();
+            Assert.assertEquals(expectedStatusCode, httpEx.getStatusLine().getStatusCode());
+            if (expectedErrorContains != null) {
+                assertTrue("Error response doesn't contain expected text", httpEx.getErrorResponse().contains(expectedErrorContains));
+            }
+        }
+    }
+
     // KEYCLOAK-3421
     @Test
     public void createClientWithUriFragment() {
@@ -262,6 +283,50 @@ public class OIDCClientRegistrationTest extends AbstractClientRegistrationTest {
 
     }
 
+    @Test
+    public void testOIDCEndpointCreateWithSamlClient() throws Exception {
+        ClientsResource clientsResource = adminClient.realm(TEST).clients();
+        ClientRepresentation samlClient = clientsResource.findByClientId("saml-client").get(0);
+        String samlClientServiceId = clientsResource.get(samlClient.getId()).getServiceAccountUser().getId();
+
+        String realmManagementId = clientsResource.findByClientId("realm-management").get(0).getId();
+        RoleRepresentation role = clientsResource.get(realmManagementId).roles().get("create-client").toRepresentation();
+
+        adminClient.realm(TEST).users().get(samlClientServiceId).roles().clientLevel(realmManagementId).add(Arrays.asList(role));
+
+        String accessToken = oauth.clientId("saml-client").doClientCredentialsGrantAccessTokenRequest("secret").getAccessToken();
+        reg.auth(Auth.token(accessToken));
+
+        // change client to saml
+        samlClient.setProtocol("saml");
+        clientsResource.get(samlClient.getId()).update(samlClient);
+
+        OIDCClientRepresentation client = createRep();
+        assertCreateFail(client, 400, Errors.INVALID_CLIENT);
+
+        // revert client
+        samlClient.setProtocol("openid-connect");
+        clientsResource.get(samlClient.getId()).update(samlClient);
+    }
+
+    @Test
+    public void testOIDCEndpointGetWithSamlClient() {
+        ClientsResource clientsResource = adminClient.realm(TEST).clients();
+        ClientRepresentation samlClient = clientsResource.findByClientId("saml-client").get(0);
+
+        reg.auth(Auth.client("saml-client", "secret"));
+
+        // change client to saml
+        samlClient.setProtocol("saml");
+        clientsResource.get(samlClient.getId()).update(samlClient);
+
+        assertGetFail(samlClient.getClientId(), 400, Errors.INVALID_CLIENT);
+
+        // revert client
+        samlClient.setProtocol("openid-connect");
+        clientsResource.get(samlClient.getId()).update(samlClient);
+    }
+
     private ClientRepresentation getKeycloakClient(String clientId) {
         return ApiUtil.findClientByClientId(adminClient.realms().realm(REALM_NAME), clientId).toRepresentation();
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/SAMLClientRegistrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/SAMLClientRegistrationTest.java
index 970780e..e764258 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/SAMLClientRegistrationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/SAMLClientRegistrationTest.java
@@ -20,22 +20,44 @@ package org.keycloak.testsuite.client;
 import org.apache.commons.io.IOUtils;
 import org.junit.Before;
 import org.junit.Test;
+import org.keycloak.admin.client.resource.ClientsResource;
 import org.keycloak.client.registration.Auth;
 import org.keycloak.client.registration.ClientRegistrationException;
+import org.keycloak.client.registration.HttpErrorException;
+import org.keycloak.events.Errors;
 import org.keycloak.representations.idm.ClientInitialAccessCreatePresentation;
 import org.keycloak.representations.idm.ClientInitialAccessPresentation;
 import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.testsuite.Assert;
+import org.keycloak.testsuite.util.KeycloakModelUtils;
 
 import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
 
 import static org.junit.Assert.assertThat;
 import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.assertTrue;
+import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
 public class SAMLClientRegistrationTest extends AbstractClientRegistrationTest {
 
+    @Override
+    public void addTestRealms(List<RealmRepresentation> testRealms) {
+        super.addTestRealms(testRealms);
+        RealmRepresentation testRealm = testRealms.get(0);
+
+        ClientRepresentation samlApp = KeycloakModelUtils.createClient(testRealm, "oidc-client");
+        samlApp.setSecret("secret");
+        samlApp.setServiceAccountsEnabled(true);
+        samlApp.setDirectAccessGrantsEnabled(true);
+    }
+
     @Before
     public void before() throws Exception {
         super.before();
@@ -61,4 +83,34 @@ public class SAMLClientRegistrationTest extends AbstractClientRegistrationTest {
         assertThat(response.getAttributes().get("saml_single_logout_service_url_redirect"), is("https://LoadBalancer-9.siroe.com:3443/federation/SPSloRedirect/metaAlias/sp"));
     }
 
+    @Test
+    public void testSAMLEndpointCreateWithOIDCClient() throws Exception {
+        ClientsResource clientsResource = adminClient.realm(TEST).clients();
+        ClientRepresentation oidcClient = clientsResource.findByClientId("oidc-client").get(0);
+        String oidcClientServiceId = clientsResource.get(oidcClient.getId()).getServiceAccountUser().getId();
+
+        String realmManagementId = clientsResource.findByClientId("realm-management").get(0).getId();
+        RoleRepresentation role = clientsResource.get(realmManagementId).roles().get("create-client").toRepresentation();
+
+        adminClient.realm(TEST).users().get(oidcClientServiceId).roles().clientLevel(realmManagementId).add(Arrays.asList(role));
+
+        String accessToken = oauth.clientId("oidc-client").doClientCredentialsGrantAccessTokenRequest("secret").getAccessToken();
+        reg.auth(Auth.token(accessToken));
+
+        String entityDescriptor = IOUtils.toString(getClass().getResourceAsStream("/clientreg-test/saml-entity-descriptor.xml"));
+        assertCreateFail(entityDescriptor, 400, Errors.INVALID_CLIENT);
+    }
+
+    private void assertCreateFail(String entityDescriptor, int expectedStatusCode, String expectedErrorContains) {
+        try {
+            reg.saml().create(entityDescriptor);
+            Assert.fail("Not expected to successfully register client");
+        } catch (ClientRegistrationException expected) {
+            HttpErrorException httpEx = (HttpErrorException) expected.getCause();
+            Assert.assertEquals(expectedStatusCode, httpEx.getStatusLine().getStatusCode());
+            if (expectedErrorContains != null) {
+                assertTrue("Error response doesn't contain expected text", httpEx.getErrorResponse().contains(expectedErrorContains));
+            }
+        }
+    }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenIntrospectionTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenIntrospectionTest.java
index 6f6bf10..2c77962 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenIntrospectionTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenIntrospectionTest.java
@@ -23,6 +23,7 @@ import org.junit.Test;
 import org.keycloak.OAuth2Constants;
 import org.keycloak.OAuthErrorException;
 import org.keycloak.crypto.Algorithm;
+import org.keycloak.events.Errors;
 import org.keycloak.jose.jws.JWSInput;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.CredentialRepresentation;
@@ -68,6 +69,11 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
         ClientRepresentation pubApp = KeycloakModelUtils.createClient(testRealm, "public-cli");
         pubApp.setPublicClient(Boolean.TRUE);
 
+        ClientRepresentation samlApp = KeycloakModelUtils.createClient(testRealm, "saml-client");
+        samlApp.setSecret("secret2");
+        samlApp.setServiceAccountsEnabled(Boolean.TRUE);
+        samlApp.setProtocol("saml");
+
         UserRepresentation user = new UserRepresentation();
         user.setUsername("no-permissions");
         CredentialRepresentation credential = new CredentialRepresentation();
@@ -350,4 +356,21 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
         assertNull(rep.getClientId());
         assertNull(rep.getSubject());
     }
+
+
+    /**
+     * Test covers the same scenario from different endpoints like TokenEndpoint and LogoutEndpoint.
+     */
+    @Test
+    public void testIntrospectWithSamlClient() throws Exception {
+        oauth.doLogin("test-user@localhost", "password");
+        String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
+        events.expectLogin().assertEvent();
+        AccessTokenResponse accessTokenResponse = oauth.doAccessTokenRequest(code, "password");
+        String tokenResponse = oauth.introspectAccessTokenWithClientCredential("saml-client", "secret2", accessTokenResponse.getAccessToken());
+        TokenMetadataRepresentation rep = JsonSerialization.readValue(tokenResponse, TokenMetadataRepresentation.class);
+
+        assertEquals(Errors.INVALID_CLIENT, rep.getOtherClaims().get("error"));
+        assertNull(rep.getSubject());
+    }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java
index 55c1dd3..21758a4 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java
@@ -29,7 +29,7 @@ import org.keycloak.events.EventType;
 import org.keycloak.jose.jws.Algorithm;
 import org.keycloak.jose.jws.JWSInput;
 import org.keycloak.jose.jws.crypto.RSAProvider;
-import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.testsuite.util.KeycloakModelUtils;
 import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
 import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
 import org.keycloak.representations.AccessTokenResponse;
@@ -86,11 +86,15 @@ public class UserInfoTest extends AbstractKeycloakTest {
 
     @Override
     public void addTestRealms(List<RealmRepresentation> testRealms) {
-
         RealmRepresentation realmRepresentation = loadJson(getClass().getResourceAsStream("/testrealm.json"), RealmRepresentation.class);
         RealmBuilder realm = RealmBuilder.edit(realmRepresentation).testEventListener();
-        testRealms.add(realm.build());
+        RealmRepresentation testRealm = realm.build();
+        testRealms.add(testRealm);
 
+        ClientRepresentation samlApp = KeycloakModelUtils.createClient(testRealm, "saml-client");
+        samlApp.setSecret("secret");
+        samlApp.setServiceAccountsEnabled(true);
+        samlApp.setDirectAccessGrantsEnabled(true);
     }
 
     @Test
@@ -351,6 +355,35 @@ public class UserInfoTest extends AbstractKeycloakTest {
         }
     }
 
+    @Test
+    public void testUserInfoRequestWithSamlClient() throws Exception {
+        // obtain an access token
+        String accessToken = oauth.doGrantAccessTokenRequest("test", "test-user@localhost", "password", null, "saml-client", "secret").getAccessToken();
+
+        // change client's protocol
+        ClientRepresentation samlClient = adminClient.realm("test").clients().findByClientId("saml-client").get(0);
+        samlClient.setProtocol("saml");
+        adminClient.realm("test").clients().get(samlClient.getId()).update(samlClient);
+
+        Client client = ClientBuilder.newClient();
+        try {
+            events.clear();
+            Response response = UserInfoClientUtil.executeUserInfoRequest_getMethod(client, accessToken);
+            response.close();
+
+            assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
+            events.expect(EventType.USER_INFO_REQUEST)
+                    .error(Errors.INVALID_CLIENT)
+                    .client((String) null)
+                    .user(Matchers.nullValue(String.class))
+                    .session(Matchers.nullValue(String.class))
+                    .detail(Details.AUTH_METHOD, Details.VALIDATE_ACCESS_TOKEN)
+                    .assertEvent();
+        } finally {
+            client.close();
+        }
+    }
+
     private AccessTokenResponse executeGrantAccessTokenRequest(Client client) {
         return executeGrantAccessTokenRequest(client, false);
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/IdpInitiatedLoginTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/IdpInitiatedLoginTest.java
index 2cabc0e..0f1dd16 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/IdpInitiatedLoginTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/IdpInitiatedLoginTest.java
@@ -16,13 +16,19 @@
  */
 package org.keycloak.testsuite.saml;
 
+import org.apache.http.client.HttpResponseException;
+import org.junit.Assert;
 import org.keycloak.admin.client.resource.ClientsResource;
 import org.keycloak.admin.client.resource.UsersResource;
+import org.keycloak.client.registration.HttpErrorException;
 import org.keycloak.dom.saml.v2.protocol.ResponseType;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.protocol.saml.SamlProtocol;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.representations.idm.UserSessionRepresentation;
 import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
+import org.keycloak.testsuite.util.ClientBuilder;
 import org.keycloak.testsuite.util.Matchers;
 import org.keycloak.testsuite.util.SamlClient.Binding;
 import org.keycloak.testsuite.util.SamlClientBuilder;
@@ -31,10 +37,16 @@ import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 import org.junit.Test;
+
+import javax.ws.rs.core.Response;
+
 import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.hasSize;
 import static org.junit.Assert.assertThat;
+import static org.keycloak.testsuite.util.Matchers.bodyHC;
+import static org.keycloak.testsuite.util.Matchers.statusCodeIsHC;
 
 /**
  *
@@ -107,4 +119,21 @@ public class IdpInitiatedLoginTest extends AbstractSamlTest {
 
     }
 
+    @Test
+    public void testIdpInitiatedLoginWithOIDCClient() {
+        ClientRepresentation clientRep = adminClient.realm(REALM_NAME).clients().findByClientId(SAML_CLIENT_ID_SALES_POST).get(0);
+        adminClient.realm(REALM_NAME).clients().get(clientRep.getId()).update(ClientBuilder.edit(clientRep)
+                .protocol(OIDCLoginProtocol.LOGIN_PROTOCOL).build());
+
+        new SamlClientBuilder()
+                .idpInitiatedLogin(getAuthServerSamlEndpoint(REALM_NAME), "sales-post").build()
+                .execute(r -> {
+                    Assert.assertThat(r, statusCodeIsHC(Response.Status.BAD_REQUEST));
+                    Assert.assertThat(r, bodyHC(containsString("Wrong client protocol.")));
+                });
+
+
+        adminClient.realm(REALM_NAME).clients().get(clientRep.getId()).update(ClientBuilder.edit(clientRep)
+                .protocol(SamlProtocol.LOGIN_PROTOCOL).build());
+    }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/SamlClientTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/SamlClientTest.java
new file mode 100644
index 0000000..b67cb8b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/SamlClientTest.java
@@ -0,0 +1,70 @@
+package org.keycloak.testsuite.saml;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.hamcrest.Matchers;
+import org.junit.Assert;
+import org.junit.Test;
+import org.keycloak.dom.saml.v2.protocol.AuthnRequestType;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.protocol.saml.SamlProtocol;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.saml.common.exceptions.ConfigurationException;
+import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.exceptions.ProcessingException;
+import org.keycloak.saml.processing.api.saml.v2.request.SAML2Request;
+import org.keycloak.testsuite.util.ClientBuilder;
+import org.keycloak.testsuite.util.SamlClient;
+import org.w3c.dom.Document;
+
+import java.io.IOException;
+import java.net.URI;
+
+/**
+ *
+ * @author mkanis
+ */
+public class SamlClientTest extends AbstractSamlTest {
+
+    @Test
+    public void testLoginWithOIDCClient() throws ParsingException, ConfigurationException, ProcessingException, IOException {
+        ClientRepresentation salesRep = adminClient.realm(REALM_NAME).clients().findByClientId(SAML_CLIENT_ID_SALES_POST).get(0);
+        adminClient.realm(REALM_NAME).clients().get(salesRep.getId()).update(ClientBuilder.edit(salesRep)
+                        .protocol(OIDCLoginProtocol.LOGIN_PROTOCOL).build());
+
+        AuthnRequestType loginRep = createLoginRequestDocument(SAML_CLIENT_ID_SALES_POST, SAML_ASSERTION_CONSUMER_URL_SALES_POST, REALM_NAME);
+        Document samlRequest = SAML2Request.convert(loginRep);
+
+        SamlClient.RedirectStrategyWithSwitchableFollowRedirect strategy = new SamlClient.RedirectStrategyWithSwitchableFollowRedirect();
+        URI samlEndpoint = getAuthServerSamlEndpoint(REALM_NAME);
+
+        try (CloseableHttpClient client = HttpClientBuilder.create().setRedirectStrategy(strategy).build()) {
+            HttpUriRequest post = SamlClient.Binding.POST.createSamlUnsignedRequest(samlEndpoint, null, samlRequest);
+            CloseableHttpResponse response = sendPost(post, client);
+            Assert.assertEquals(response.getStatusLine().getStatusCode(), 400);
+            String s = IOUtils.toString(response.getEntity().getContent(), "UTF-8");
+            Assert.assertThat(s, Matchers.containsString("Wrong client protocol."));
+
+            response.close();
+        }
+
+        adminClient.realm(REALM_NAME).clients().get(salesRep.getId()).update(ClientBuilder.edit(salesRep)
+                .protocol(SamlProtocol.LOGIN_PROTOCOL).build());
+    }
+
+    private CloseableHttpResponse sendPost(HttpUriRequest post, final CloseableHttpClient client) {
+        CloseableHttpResponse response;
+        try {
+            HttpClientContext context = HttpClientContext.create();
+            response = client.execute(post, context);
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+
+        return response;
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/KeycloakModelUtils.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/KeycloakModelUtils.java
index eda966d..10a737a 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/KeycloakModelUtils.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/KeycloakModelUtils.java
@@ -23,6 +23,9 @@ import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 
+import java.util.Arrays;
+import java.util.List;
+
 import static org.keycloak.models.utils.KeycloakModelUtils.getDefaultClientAuthenticatorType;
 
 /**
@@ -37,7 +40,12 @@ public class KeycloakModelUtils {
         ClientRepresentation app = new ClientRepresentation();
         app.setName(name);
         app.setClientId(name);
-        realm.getClients().add(app);
+        List<ClientRepresentation> clients = realm.getClients();
+        if (clients != null) {
+            clients.add(app);
+        } else {
+            realm.setClients(Arrays.asList(app));
+        }
         app.setClientAuthenticatorType(getDefaultClientAuthenticatorType());
         generateSecret(app);
         app.setFullScopeAllowed(true);