Added realm registration
This commit is contained in:
parent
0ffe1cb354
commit
92235e3b07
17 changed files with 560 additions and 329 deletions
|
@ -5,6 +5,7 @@
|
|||
"accessCodeLifespan": 10,
|
||||
"sslNotRequired": true,
|
||||
"cookieLoginAllowed": true,
|
||||
"registrationAllowed": true,
|
||||
"privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
|
||||
"publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||
"requiredCredentials": [ "password" ],
|
||||
|
|
|
@ -103,6 +103,7 @@ public class RealmManager {
|
|||
newRealm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
|
||||
newRealm.setSslNotRequired(rep.isSslNotRequired());
|
||||
newRealm.setCookieLoginAllowed(rep.isCookieLoginAllowed());
|
||||
newRealm.setRegistrationAllowed(rep.isRegistrationAllowed());
|
||||
if (rep.getPrivateKey() == null || rep.getPublicKey() == null) {
|
||||
generateRealmKeys(newRealm);
|
||||
} else {
|
||||
|
|
|
@ -62,19 +62,19 @@ public class RequiredCredentialModel {
|
|||
PASSWORD.setType(CredentialRepresentation.PASSWORD);
|
||||
PASSWORD.setInput(true);
|
||||
PASSWORD.setSecret(true);
|
||||
PASSWORD.setFormLabel("Password");
|
||||
PASSWORD.setFormLabel("password");
|
||||
map.put(PASSWORD.getType(), PASSWORD);
|
||||
TOTP = new RequiredCredentialModel();
|
||||
TOTP.setType(CredentialRepresentation.TOTP);
|
||||
TOTP.setInput(true);
|
||||
TOTP.setSecret(false);
|
||||
TOTP.setFormLabel("Authenticator Code");
|
||||
TOTP.setFormLabel("authenticatorCode");
|
||||
map.put(TOTP.getType(), TOTP);
|
||||
CLIENT_CERT = new RequiredCredentialModel();
|
||||
CLIENT_CERT.setType(CredentialRepresentation.CLIENT_CERT);
|
||||
CLIENT_CERT.setInput(false);
|
||||
CLIENT_CERT.setSecret(false);
|
||||
CLIENT_CERT.setFormLabel("Client Certificate");
|
||||
CLIENT_CERT.setFormLabel("clientCertificate");
|
||||
map.put(CLIENT_CERT.getType(), CLIENT_CERT);
|
||||
BUILT_IN = Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
|
|
@ -1,104 +0,0 @@
|
|||
package org.keycloak.services.resources;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.jboss.resteasy.logging.Logger;
|
||||
import org.jboss.resteasy.spi.HttpRequest;
|
||||
import org.keycloak.services.JspRequestParameters;
|
||||
import org.keycloak.services.managers.AccessCodeEntry;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.managers.TokenManager;
|
||||
import org.keycloak.services.models.RealmModel;
|
||||
import org.keycloak.services.models.RoleModel;
|
||||
import org.keycloak.services.models.UserModel;
|
||||
|
||||
public class OAuthUtil {
|
||||
|
||||
private static final Logger log = Logger.getLogger(OAuthUtil.class);
|
||||
|
||||
public final static String securityFailurePath = "/saas/securityFailure.jsp";
|
||||
public final static String oauthFormPath = "/saas/oauthGrantForm.jsp";
|
||||
|
||||
public static Response processAccessCode(RealmModel realm, TokenManager tokenManager, AuthenticationManager authManager,
|
||||
HttpRequest request, UriInfo uriInfo,
|
||||
String scopeParam, String state,
|
||||
String redirect,
|
||||
UserModel client, UserModel user) {
|
||||
RoleModel resourceRole = realm.getRole(RealmManager.RESOURCE_ROLE);
|
||||
RoleModel identityRequestRole = realm.getRole(RealmManager.IDENTITY_REQUESTER_ROLE);
|
||||
boolean isResource = realm.hasRole(client, resourceRole);
|
||||
if (!isResource && !realm.hasRole(client, identityRequestRole)) {
|
||||
securityFailureForward(request, "Login requester not allowed to request login.");
|
||||
return null;
|
||||
}
|
||||
AccessCodeEntry accessCode = tokenManager.createAccessCode(scopeParam, state, redirect, realm, client, user);
|
||||
log.info("processAccessCode: isResource: " + isResource);
|
||||
log.info(
|
||||
"processAccessCode: go to oauth page?: "
|
||||
+ (!isResource && (accessCode.getRealmRolesRequested().size() > 0 || accessCode
|
||||
.getResourceRolesRequested().size() > 0)));
|
||||
if (!isResource
|
||||
&& (accessCode.getRealmRolesRequested().size() > 0 || accessCode.getResourceRolesRequested().size() > 0)) {
|
||||
oauthGrantPage(realm, request, uriInfo, accessCode, client);
|
||||
return null;
|
||||
}
|
||||
return redirectAccessCode(realm, authManager, uriInfo, accessCode, state, redirect);
|
||||
}
|
||||
|
||||
public static void securityFailureForward(HttpRequest request, String message) {
|
||||
log.error(message);
|
||||
request.setAttribute(JspRequestParameters.KEYCLOAK_SECURITY_FAILURE_MESSAGE, message);
|
||||
request.forward(securityFailurePath);
|
||||
}
|
||||
|
||||
public static Response redirectAccessCode(RealmModel realm, AuthenticationManager authManager, UriInfo uriInfo,
|
||||
AccessCodeEntry accessCode,
|
||||
String state, String redirect) {
|
||||
String code = accessCode.getCode();
|
||||
UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("code", code);
|
||||
log.info("redirectAccessCode: state: " + state);
|
||||
if (state != null)
|
||||
redirectUri.queryParam("state", state);
|
||||
Response.ResponseBuilder location = Response.status(302).location(redirectUri.build());
|
||||
if (realm.isCookieLoginAllowed()) {
|
||||
location.cookie(authManager.createLoginCookie(realm, accessCode.getUser(), uriInfo));
|
||||
}
|
||||
return location.build();
|
||||
}
|
||||
|
||||
public static void forwardToLoginForm(RealmModel realm, HttpRequest request, UriInfo uriInfo, String redirect,
|
||||
String clientId, String scopeParam, String state) {
|
||||
request.setAttribute(RealmModel.class.getName(), realm);
|
||||
|
||||
request.setAttribute("KEYCLOAK_LOGIN_PAGE", Urls.realmLoginPage(uriInfo, realm.getId()));
|
||||
request.setAttribute("KEYCLOAK_LOGIN_ACTION", Urls.realmLoginAction(uriInfo, realm.getId()));
|
||||
|
||||
request.setAttribute("KEYCLOAK_REGISTRATION_PAGE", Urls.realmRegisterPage(uriInfo, realm.getId()));
|
||||
request.setAttribute("KEYCLOAK_REGISTRATION_ACTION", Urls.realmRegisterAction(uriInfo, realm.getId()));
|
||||
|
||||
request.setAttribute("KEYCLOAK_SOCIAL_LOGIN", Urls.socialRedirectToProviderAuth(uriInfo, realm.getId()));
|
||||
|
||||
// RESTEASY eats the form data, so we send via an attribute
|
||||
request.setAttribute("redirect_uri", redirect);
|
||||
request.setAttribute("client_id", clientId);
|
||||
request.setAttribute("scope", scopeParam);
|
||||
request.setAttribute("state", state);
|
||||
|
||||
request.forward(Pages.loginForm);
|
||||
}
|
||||
|
||||
public static void oauthGrantPage(RealmModel realm, HttpRequest request, UriInfo uriInfo, AccessCodeEntry accessCode,
|
||||
UserModel client) {
|
||||
request.setAttribute("realmRolesRequested", accessCode.getRealmRolesRequested());
|
||||
request.setAttribute("resourceRolesRequested", accessCode.getResourceRolesRequested());
|
||||
request.setAttribute("client", client);
|
||||
request.setAttribute("action", TokenService.processOAuthUrl(uriInfo).build(realm.getId()).toString());
|
||||
request.setAttribute("code", accessCode.getCode());
|
||||
|
||||
request.forward(oauthFormPath);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
package org.keycloak.services.resources;
|
||||
|
||||
public class Pages {
|
||||
|
||||
public final static String loginForm = "/sdk/login.xhtml";
|
||||
public final static String registerForm = "/sdk/register.xhtml";
|
||||
|
||||
}
|
|
@ -14,9 +14,11 @@ import org.keycloak.services.models.RoleModel;
|
|||
import org.keycloak.services.models.UserCredentialModel;
|
||||
import org.keycloak.services.models.UserModel;
|
||||
import org.keycloak.services.resources.admin.RealmsAdminResource;
|
||||
import org.keycloak.services.resources.flows.Flows;
|
||||
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.*;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
|
@ -81,7 +83,8 @@ public class SaasService {
|
|||
public Response callImpl() {
|
||||
RealmManager realmManager = new RealmManager(session);
|
||||
RealmModel realm = realmManager.defaultRealm();
|
||||
if (realm == null) throw new NotFoundException();
|
||||
if (realm == null)
|
||||
throw new NotFoundException();
|
||||
UserModel user = authManager.authenticateSaasIdentityCookie(realm, uriInfo, headers);
|
||||
if (user == null) {
|
||||
return Response.status(401).build();
|
||||
|
@ -102,7 +105,8 @@ public class SaasService {
|
|||
public Response callImpl() {
|
||||
RealmManager realmManager = new RealmManager(session);
|
||||
RealmModel realm = realmManager.defaultRealm();
|
||||
if (realm == null) throw new NotFoundException();
|
||||
if (realm == null)
|
||||
throw new NotFoundException();
|
||||
UserModel user = authManager.authenticateSaasIdentityCookie(realm, uriInfo, headers);
|
||||
if (user == null) {
|
||||
return Response.status(401).build();
|
||||
|
@ -137,7 +141,6 @@ public class SaasService {
|
|||
}.call();
|
||||
}
|
||||
|
||||
|
||||
public static UriBuilder contextRoot(UriInfo uriInfo) {
|
||||
return UriBuilder.fromUri(uriInfo.getBaseUri()).replacePath("/auth-server");
|
||||
}
|
||||
|
@ -153,7 +156,8 @@ public class SaasService {
|
|||
protected RealmsAdminResource callImpl() {
|
||||
RealmManager realmManager = new RealmManager(session);
|
||||
RealmModel saasRealm = realmManager.defaultRealm();
|
||||
if (saasRealm == null) throw new NotFoundException();
|
||||
if (saasRealm == null)
|
||||
throw new NotFoundException();
|
||||
UserModel admin = authManager.authenticateSaasIdentity(saasRealm, uriInfo, headers);
|
||||
if (admin == null) {
|
||||
throw new NotAuthorizedException("Bearer");
|
||||
|
@ -178,7 +182,8 @@ public class SaasService {
|
|||
RealmManager realmManager = new RealmManager(session);
|
||||
RealmModel realm = realmManager.defaultRealm();
|
||||
authManager.expireSaasIdentityCookie(uriInfo);
|
||||
forwardToLoginForm(realm, null, null);
|
||||
|
||||
Flows.forms(realm, request).forwardToLogin();
|
||||
}
|
||||
}.run();
|
||||
}
|
||||
|
@ -193,7 +198,8 @@ public class SaasService {
|
|||
RealmManager realmManager = new RealmManager(session);
|
||||
RealmModel realm = realmManager.defaultRealm();
|
||||
authManager.expireSaasIdentityCookie(uriInfo);
|
||||
forwardToRegisterForm(realm, null, null);
|
||||
|
||||
Flows.forms(realm, request).forwardToRegistration();
|
||||
}
|
||||
}.run();
|
||||
}
|
||||
|
@ -208,12 +214,12 @@ public class SaasService {
|
|||
RealmManager realmManager = new RealmManager(session);
|
||||
RealmModel realm = realmManager.defaultRealm();
|
||||
authManager.expireSaasIdentityCookie(uriInfo);
|
||||
forwardToLoginForm(realm, null, null);
|
||||
|
||||
Flows.forms(realm, request).forwardToLogin();
|
||||
}
|
||||
}.run();
|
||||
}
|
||||
|
||||
|
||||
@Path("logout-cookie")
|
||||
@GET
|
||||
@NoCache
|
||||
|
@ -227,45 +233,6 @@ public class SaasService {
|
|||
}.run();
|
||||
}
|
||||
|
||||
protected void forwardToLoginForm(RealmModel realm, String error, MultivaluedMap<String, String> formData) {
|
||||
if (error != null) {
|
||||
request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", error);
|
||||
}
|
||||
|
||||
if (formData != null) {
|
||||
request.setAttribute("KEYCLOAK_FORM_DATA", formData);
|
||||
}
|
||||
|
||||
forwardToForm(realm, Pages.loginForm);
|
||||
}
|
||||
|
||||
protected void forwardToRegisterForm(RealmModel realm, String error, MultivaluedMap<String, String> formData) {
|
||||
if (error != null) {
|
||||
request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", error);
|
||||
}
|
||||
|
||||
if (formData != null) {
|
||||
request.setAttribute("KEYCLOAK_FORM_DATA", formData);
|
||||
}
|
||||
|
||||
forwardToForm(realm, Pages.registerForm);
|
||||
}
|
||||
|
||||
protected void forwardToForm(RealmModel realm, String form) {
|
||||
request.setAttribute(RealmModel.class.getName(), realm);
|
||||
|
||||
request.setAttribute("KEYCLOAK_LOGIN_PAGE", Urls.saasLoginPage(uriInfo));
|
||||
request.setAttribute("KEYCLOAK_LOGIN_ACTION", Urls.saasLoginAction(uriInfo));
|
||||
|
||||
request.setAttribute("KEYCLOAK_REGISTRATION_PAGE", Urls.saasRegisterPage(uriInfo));
|
||||
request.setAttribute("KEYCLOAK_REGISTRATION_ACTION", Urls.saasRegisterAction(uriInfo));
|
||||
|
||||
request.setAttribute("KEYCLOAK_SOCIAL_LOGIN", Urls.socialRedirectToProviderAuth(uriInfo, realm.getId()));
|
||||
|
||||
request.forward(form);
|
||||
}
|
||||
|
||||
|
||||
@Path("login")
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
|
@ -276,7 +243,8 @@ public class SaasService {
|
|||
protected Response callImpl() {
|
||||
RealmManager realmManager = new RealmManager(session);
|
||||
RealmModel realm = realmManager.defaultRealm();
|
||||
if (realm == null) throw new NotFoundException();
|
||||
if (realm == null)
|
||||
throw new NotFoundException();
|
||||
|
||||
if (!realm.isEnabled()) {
|
||||
throw new NotImplementedYetException();
|
||||
|
@ -285,26 +253,27 @@ public class SaasService {
|
|||
UserModel user = realm.getUser(username);
|
||||
if (user == null) {
|
||||
logger.info("Not Authenticated! Incorrect user name");
|
||||
forwardToLoginForm(realm, "Invalid username or password", formData);
|
||||
return null;
|
||||
|
||||
return Flows.forms(realm, request).setError("Invalid username or password").setFormData(formData)
|
||||
.forwardToLogin();
|
||||
}
|
||||
if (!user.isEnabled()) {
|
||||
logger.info("NAccount is disabled, contact admin.");
|
||||
forwardToLoginForm(realm, "Account is disabled, contact admin.", formData);
|
||||
return null;
|
||||
|
||||
return Flows.forms(realm, request).setError("Invalid username or password")
|
||||
.setFormData(formData).forwardToLogin();
|
||||
}
|
||||
|
||||
boolean authenticated = authManager.authenticateForm(realm, user, formData);
|
||||
if (!authenticated) {
|
||||
logger.info("Not Authenticated! Invalid credentials");
|
||||
forwardToLoginForm(realm, "Invalid username or password", formData);
|
||||
return null;
|
||||
|
||||
return Flows.forms(realm, request).setError("Invalid username or password").setFormData(formData)
|
||||
.forwardToLogin();
|
||||
}
|
||||
|
||||
NewCookie cookie = authManager.createSaasIdentityCookie(realm, user, uriInfo);
|
||||
return Response.status(302)
|
||||
.cookie(cookie)
|
||||
.location(contextRoot(uriInfo).path(adminPath).build()).build();
|
||||
return Response.status(302).cookie(cookie).location(contextRoot(uriInfo).path(adminPath).build()).build();
|
||||
}
|
||||
}.call();
|
||||
}
|
||||
|
@ -340,8 +309,8 @@ public class SaasService {
|
|||
|
||||
String error = validateRegistrationForm(formData);
|
||||
if (error != null) {
|
||||
forwardToRegisterForm(defaultRealm, error, formData);
|
||||
return null;
|
||||
return Flows.forms(defaultRealm, request).setError(error).setFormData(formData)
|
||||
.forwardToRegistration();
|
||||
}
|
||||
|
||||
UserRepresentation newUser = new UserRepresentation();
|
||||
|
@ -366,16 +335,16 @@ public class SaasService {
|
|||
last = token;
|
||||
}
|
||||
}
|
||||
if (first == null) first = new StringBuffer();
|
||||
if (first == null)
|
||||
first = new StringBuffer();
|
||||
newUser.setFirstName(first.toString());
|
||||
newUser.setLastName(last);
|
||||
}
|
||||
newUser.credential(CredentialRepresentation.PASSWORD, formData.getFirst("password"));
|
||||
UserModel user = registerMe(defaultRealm, newUser);
|
||||
if (user == null) {
|
||||
request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", "Username already exists.");
|
||||
forwardToRegisterForm(defaultRealm, "Username already exists.", formData);
|
||||
return null;
|
||||
return Flows.forms(defaultRealm, request).setError("Username already exists.")
|
||||
.setFormData(formData).forwardToRegistration();
|
||||
|
||||
}
|
||||
NewCookie cookie = authManager.createSaasIdentityCookie(defaultRealm, user, uriInfo);
|
||||
|
@ -384,7 +353,6 @@ public class SaasService {
|
|||
}.call();
|
||||
}
|
||||
|
||||
|
||||
protected UserModel registerMe(RealmModel defaultRealm, UserRepresentation newUser) {
|
||||
if (!defaultRealm.isEnabled()) {
|
||||
throw new ForbiddenException();
|
||||
|
|
|
@ -16,7 +16,6 @@ import javax.ws.rs.core.Context;
|
|||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.jboss.resteasy.logging.Logger;
|
||||
|
@ -25,7 +24,11 @@ import org.keycloak.services.managers.AuthenticationManager;
|
|||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.managers.TokenManager;
|
||||
import org.keycloak.services.models.RealmModel;
|
||||
import org.keycloak.services.models.RoleModel;
|
||||
import org.keycloak.services.models.UserModel;
|
||||
import org.keycloak.services.resources.flows.Flows;
|
||||
import org.keycloak.services.resources.flows.OAuthFlows;
|
||||
import org.keycloak.services.resources.flows.Urls;
|
||||
import org.keycloak.social.AuthCallback;
|
||||
import org.keycloak.social.AuthRequest;
|
||||
import org.keycloak.social.RequestDetails;
|
||||
|
@ -61,19 +64,6 @@ public class SocialResource {
|
|||
this.socialRequestManager = socialRequestManager;
|
||||
}
|
||||
|
||||
public static UriBuilder socialServiceBaseUrl(UriInfo uriInfo) {
|
||||
UriBuilder base = uriInfo.getBaseUriBuilder().path(SocialResource.class);
|
||||
return base;
|
||||
}
|
||||
|
||||
public static UriBuilder redirectToProviderAuthUrl(UriInfo uriInfo) {
|
||||
return socialServiceBaseUrl(uriInfo).path(SocialResource.class, "redirectToProviderAuth");
|
||||
}
|
||||
|
||||
public static UriBuilder callbackUrl(UriInfo uriInfo) {
|
||||
return socialServiceBaseUrl(uriInfo).path(SocialResource.class, "callback");
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("callback")
|
||||
public Response callback() throws URISyntaxException {
|
||||
|
@ -86,10 +76,32 @@ public class SocialResource {
|
|||
|
||||
String realmId = requestData.getClientAttribute("realmId");
|
||||
|
||||
RealmManager realmManager = new RealmManager(session);
|
||||
RealmModel realm = realmManager.getRealm(realmId);
|
||||
|
||||
OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
|
||||
|
||||
if (!realm.isEnabled()) {
|
||||
return oauth.forwardToSecurityFailure("Realm not enabled.");
|
||||
}
|
||||
|
||||
if (!realm.isEnabled()) {
|
||||
return oauth.forwardToSecurityFailure("Realm not enabled.");
|
||||
}
|
||||
|
||||
String clientId = requestData.getClientAttributes().get("clientId");
|
||||
|
||||
UserModel client = realm.getUser(clientId);
|
||||
if (client == null) {
|
||||
return oauth.forwardToSecurityFailure("Unknown login requester.");
|
||||
}
|
||||
if (!client.isEnabled()) {
|
||||
return oauth.forwardToSecurityFailure("Login requester not enabled.");
|
||||
}
|
||||
|
||||
String key = System.getProperty("keycloak.social." + requestData.getProviderId() + ".key");
|
||||
String secret = System.getProperty("keycloak.social." + requestData.getProviderId() + ".secret");
|
||||
String callbackUri = callbackUrl(uriInfo).build().toString();
|
||||
|
||||
String callbackUri = Urls.socialCallback(uriInfo.getBaseUri()).toString();
|
||||
SocialProviderConfig config = new SocialProviderConfig(key, secret, callbackUri);
|
||||
|
||||
AuthCallback callback = new AuthCallback(requestData.getSocialAttributes(), queryParams);
|
||||
|
@ -99,28 +111,7 @@ public class SocialResource {
|
|||
socialUser = provider.processCallback(config, callback);
|
||||
} catch (SocialProviderException e) {
|
||||
logger.warn("Failed to process social callback", e);
|
||||
OAuthUtil.securityFailureForward(request, "Failed to process social callback");
|
||||
return null;
|
||||
}
|
||||
|
||||
RealmManager realmManager = new RealmManager(session);
|
||||
RealmModel realm = realmManager.getRealm(realmId);
|
||||
|
||||
if (!realm.isEnabled()) {
|
||||
OAuthUtil.securityFailureForward(request, "Realm not enabled.");
|
||||
return null;
|
||||
}
|
||||
|
||||
String clientId = requestData.getClientAttributes().get("clientId");
|
||||
|
||||
UserModel client = realm.getUser(clientId);
|
||||
if (client == null) {
|
||||
OAuthUtil.securityFailureForward(request, "Unknown login requester.");
|
||||
return null;
|
||||
}
|
||||
if (!client.isEnabled()) {
|
||||
OAuthUtil.securityFailureForward(request, "Login requester not enabled.");
|
||||
return null;
|
||||
return oauth.forwardToSecurityFailure("Failed to process social callback");
|
||||
}
|
||||
|
||||
// TODO Lookup user based on attribute for provider id - this is so a user can have a friendly username + link a
|
||||
|
@ -133,20 +124,20 @@ public class SocialResource {
|
|||
user.setAttribute(provider.getId() + ".id", socialUser.getId());
|
||||
|
||||
// TODO Grant default roles for realm when available
|
||||
realm.grantRole(user, realm.getRole("user"));
|
||||
RoleModel defaultRole = realm.getRole("user");
|
||||
|
||||
realm.grantRole(user, defaultRole);
|
||||
}
|
||||
|
||||
if (!user.isEnabled()) {
|
||||
OAuthUtil.securityFailureForward(request, "Your account is not enabled.");
|
||||
return null;
|
||||
return oauth.forwardToSecurityFailure("Your account is not enabled.");
|
||||
}
|
||||
|
||||
String scope = requestData.getClientAttributes().get("scope");
|
||||
String state = requestData.getClientAttributes().get("state");
|
||||
String redirectUri = requestData.getClientAttributes().get("redirectUri");
|
||||
|
||||
return OAuthUtil.processAccessCode(realm, tokenManager, authManager, request, uriInfo, scope, state,
|
||||
redirectUri, client, user);
|
||||
return oauth.processAccessCode(scope, state, redirectUri, client, user);
|
||||
}
|
||||
}.call();
|
||||
}
|
||||
|
@ -159,13 +150,12 @@ public class SocialResource {
|
|||
@QueryParam("redirect_uri") final String redirectUri) {
|
||||
SocialProvider provider = getProvider(providerId);
|
||||
if (provider == null) {
|
||||
OAuthUtil.securityFailureForward(request, "Social provider not found");
|
||||
return null;
|
||||
return Flows.pages(request).forwardToSecurityFailure("Social provider not found");
|
||||
}
|
||||
|
||||
String key = System.getProperty("keycloak.social." + providerId + ".key");
|
||||
String secret = System.getProperty("keycloak.social." + providerId + ".secret");
|
||||
String callbackUri = callbackUrl(uriInfo).build().toString();
|
||||
String callbackUri = Urls.socialCallback(uriInfo.getBaseUri()).toString();
|
||||
|
||||
SocialProviderConfig config = new SocialProviderConfig(key, secret, callbackUri);
|
||||
|
||||
|
@ -181,9 +171,7 @@ public class SocialResource {
|
|||
|
||||
return Response.status(Status.FOUND).location(authRequest.getAuthUri()).build();
|
||||
} catch (Throwable t) {
|
||||
logger.error("Failed to redirect to social auth", t);
|
||||
OAuthUtil.securityFailureForward(request, "Failed to redirect to social auth");
|
||||
return null;
|
||||
return Flows.pages(request).forwardToSecurityFailure("Failed to redirect to social auth");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@ import org.jboss.resteasy.spi.HttpRequest;
|
|||
import org.jboss.resteasy.spi.HttpResponse;
|
||||
import org.keycloak.representations.AccessTokenResponse;
|
||||
import org.keycloak.representations.SkeletonKeyToken;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.services.managers.AccessCodeEntry;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
|
@ -17,9 +19,13 @@ import org.keycloak.services.managers.ResourceAdminManager;
|
|||
import org.keycloak.services.managers.TokenManager;
|
||||
import org.keycloak.services.models.RealmModel;
|
||||
import org.keycloak.services.models.RoleModel;
|
||||
import org.keycloak.services.models.UserCredentialModel;
|
||||
import org.keycloak.services.models.UserModel;
|
||||
import org.keycloak.services.resources.flows.Flows;
|
||||
import org.keycloak.services.resources.flows.OAuthFlows;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.ForbiddenException;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.NotAuthorizedException;
|
||||
import javax.ws.rs.POST;
|
||||
|
@ -30,14 +36,17 @@ import javax.ws.rs.core.Context;
|
|||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.NewCookie;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.SecurityContext;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import javax.ws.rs.ext.Providers;
|
||||
|
||||
import java.security.PrivateKey;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
|
@ -72,8 +81,7 @@ public class TokenService {
|
|||
}
|
||||
|
||||
public static UriBuilder tokenServiceBaseUrl(UriInfo uriInfo) {
|
||||
UriBuilder base = uriInfo.getBaseUriBuilder()
|
||||
.path(RealmsResource.class).path(RealmsResource.class, "getTokenService");
|
||||
UriBuilder base = uriInfo.getBaseUriBuilder().path(RealmsResource.class).path(RealmsResource.class, "getTokenService");
|
||||
return base;
|
||||
}
|
||||
|
||||
|
@ -104,7 +112,6 @@ public class TokenService {
|
|||
return tokenServiceBaseUrl(uriInfo).path(TokenService.class, "processOAuth");
|
||||
}
|
||||
|
||||
|
||||
@Path("grants/identity-token")
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
|
@ -174,52 +181,126 @@ public class TokenService {
|
|||
@Path("auth/request/login")
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
public Response processLogin(final MultivaluedMap<String, String> formData) {
|
||||
public Response processLogin(@QueryParam("client_id") final String clientId, @QueryParam("scope") final String scopeParam,
|
||||
@QueryParam("state") final String state, @QueryParam("redirect_uri") final String redirect,
|
||||
final MultivaluedMap<String, String> formData) {
|
||||
return new Transaction() {
|
||||
protected Response callImpl() {
|
||||
String clientId = formData.getFirst("client_id");
|
||||
String scopeParam = formData.getFirst("scope");
|
||||
String state = formData.getFirst("state");
|
||||
String redirect = formData.getFirst("redirect_uri");
|
||||
OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
|
||||
|
||||
if (!realm.isEnabled()) {
|
||||
OAuthUtil.securityFailureForward(request, "Realm not enabled.");
|
||||
return null;
|
||||
return oauth.forwardToSecurityFailure("Realm not enabled.");
|
||||
}
|
||||
UserModel client = realm.getUser(clientId);
|
||||
if (client == null) {
|
||||
OAuthUtil.securityFailureForward(request, "Unknown login requester.");
|
||||
return null;
|
||||
return oauth.forwardToSecurityFailure("Unknown login requester.");
|
||||
}
|
||||
if (!client.isEnabled()) {
|
||||
OAuthUtil.securityFailureForward(request, "Login requester not enabled.");
|
||||
return null;
|
||||
return oauth.forwardToSecurityFailure("Login requester not enabled.");
|
||||
}
|
||||
String username = formData.getFirst("username");
|
||||
UserModel user = realm.getUser(username);
|
||||
if (user == null) {
|
||||
logger.error("Incorrect user name.");
|
||||
request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", "Invalid username or password");
|
||||
request.setAttribute("KEYCLOAK_FORM_DATA", formData);
|
||||
OAuthUtil.forwardToLoginForm(realm, request, uriInfo, redirect, clientId, scopeParam, state);
|
||||
return null;
|
||||
|
||||
return Flows.forms(realm, request).setError("Invalid username or password").setFormData(formData)
|
||||
.forwardToLogin();
|
||||
}
|
||||
if (!user.isEnabled()) {
|
||||
OAuthUtil.securityFailureForward(request, "Your account is not enabled.");
|
||||
return null;
|
||||
return oauth.forwardToSecurityFailure("Your account is not enabled.");
|
||||
}
|
||||
boolean authenticated = authManager.authenticateForm(realm, user, formData);
|
||||
if (!authenticated) {
|
||||
logger.error("Authentication failed");
|
||||
request.setAttribute("username", username);
|
||||
request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", "Invalid username or password");
|
||||
request.setAttribute("KEYCLOAK_FORM_DATA", formData);
|
||||
OAuthUtil.forwardToLoginForm(realm, request, uriInfo, redirect, clientId, scopeParam, state);
|
||||
return null;
|
||||
|
||||
return Flows.forms(realm, request).setError("Invalid username or password").setFormData(formData)
|
||||
.forwardToLogin();
|
||||
}
|
||||
|
||||
return OAuthUtil.processAccessCode(realm, tokenManager, authManager, request, uriInfo, scopeParam, state,
|
||||
redirect, client, user);
|
||||
return oauth.processAccessCode(scopeParam, state, redirect, client, user);
|
||||
}
|
||||
}.call();
|
||||
}
|
||||
|
||||
@Path("registrations")
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
public Response processRegister(@QueryParam("client_id") final String clientId,
|
||||
@QueryParam("scope") final String scopeParam, @QueryParam("state") final String state,
|
||||
@QueryParam("redirect_uri") final String redirect, final MultivaluedMap<String, String> formData) {
|
||||
return new Transaction() {
|
||||
@Override
|
||||
protected Response callImpl() {
|
||||
OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
|
||||
|
||||
if (!realm.isEnabled()) {
|
||||
return oauth.forwardToSecurityFailure("Realm not enabled");
|
||||
}
|
||||
UserModel client = realm.getUser(clientId);
|
||||
if (client == null) {
|
||||
return oauth.forwardToSecurityFailure("Unknown login requester.");
|
||||
}
|
||||
|
||||
if (!client.isEnabled()) {
|
||||
return oauth.forwardToSecurityFailure("Login requester not enabled.");
|
||||
}
|
||||
|
||||
if (!realm.isRegistrationAllowed()) {
|
||||
return oauth.forwardToSecurityFailure("Registration not allowed");
|
||||
}
|
||||
|
||||
String error = validateRegistrationForm(formData);
|
||||
if (error != null) {
|
||||
return Flows.forms(realm, request).setError(error).setFormData(formData).forwardToRegistration();
|
||||
}
|
||||
|
||||
String username = formData.getFirst("username");
|
||||
|
||||
UserModel user = realm.getUser(username);
|
||||
if (user != null) {
|
||||
return Flows.forms(realm, request).setError("Username already exists.").setFormData(formData)
|
||||
.forwardToRegistration();
|
||||
}
|
||||
|
||||
user = realm.addUser(username);
|
||||
|
||||
String fullname = formData.getFirst("name");
|
||||
if (fullname != null) {
|
||||
StringTokenizer tokenizer = new StringTokenizer(fullname, " ");
|
||||
StringBuffer first = null;
|
||||
String last = "";
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
String token = tokenizer.nextToken();
|
||||
if (tokenizer.hasMoreTokens()) {
|
||||
if (first == null) {
|
||||
first = new StringBuffer();
|
||||
} else {
|
||||
first.append(" ");
|
||||
}
|
||||
first.append(token);
|
||||
} else {
|
||||
last = token;
|
||||
}
|
||||
}
|
||||
if (first == null)
|
||||
first = new StringBuffer();
|
||||
user.setFirstName(first.toString());
|
||||
user.setLastName(last);
|
||||
}
|
||||
|
||||
user.setEmail(formData.getFirst("email"));
|
||||
|
||||
UserCredentialModel credentials = new UserCredentialModel();
|
||||
credentials.setType(CredentialRepresentation.PASSWORD);
|
||||
credentials.setValue(formData.getFirst("password"));
|
||||
realm.updateCredential(user, credentials);
|
||||
|
||||
// TODO Grant default roles for realm when available
|
||||
RoleModel defaultRole = realm.getRole("user");
|
||||
|
||||
realm.grantRole(user, defaultRole);
|
||||
|
||||
return processLogin(clientId, scopeParam, state, redirect, formData);
|
||||
}
|
||||
}.call();
|
||||
}
|
||||
|
@ -276,7 +357,6 @@ public class TokenService {
|
|||
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
|
||||
}
|
||||
|
||||
|
||||
JWSInput input = new JWSInput(code, providers);
|
||||
boolean verifiedCode = false;
|
||||
try {
|
||||
|
@ -288,7 +368,8 @@ public class TokenService {
|
|||
Map<String, String> res = new HashMap<String, String>();
|
||||
res.put("error", "invalid_grant");
|
||||
res.put("error_description", "Unable to verify code signature");
|
||||
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
|
||||
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
|
||||
.build();
|
||||
}
|
||||
String key = input.readContent(String.class);
|
||||
AccessCodeEntry accessCode = tokenManager.pullAccessCode(key);
|
||||
|
@ -296,25 +377,29 @@ public class TokenService {
|
|||
Map<String, String> res = new HashMap<String, String>();
|
||||
res.put("error", "invalid_grant");
|
||||
res.put("error_description", "Code not found");
|
||||
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
|
||||
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
|
||||
.build();
|
||||
}
|
||||
if (accessCode.isExpired()) {
|
||||
Map<String, String> res = new HashMap<String, String>();
|
||||
res.put("error", "invalid_grant");
|
||||
res.put("error_description", "Code is expired");
|
||||
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
|
||||
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
|
||||
.build();
|
||||
}
|
||||
if (!accessCode.getToken().isActive()) {
|
||||
Map<String, String> res = new HashMap<String, String>();
|
||||
res.put("error", "invalid_grant");
|
||||
res.put("error_description", "Token expired");
|
||||
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
|
||||
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
|
||||
.build();
|
||||
}
|
||||
if (!client.getLoginName().equals(accessCode.getClient().getLoginName())) {
|
||||
Map<String, String> res = new HashMap<String, String>();
|
||||
res.put("error", "invalid_grant");
|
||||
res.put("error_description", "Auth error");
|
||||
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
|
||||
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
|
||||
.build();
|
||||
}
|
||||
logger.info("accessRequest SUCCESS");
|
||||
AccessTokenResponse res = accessTokenResponse(realm.getPrivateKey(), accessCode.getToken());
|
||||
|
@ -331,9 +416,7 @@ public class TokenService {
|
|||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
String encodedToken = new JWSBuilder()
|
||||
.content(tokenBytes)
|
||||
.rsa256(privateKey);
|
||||
String encodedToken = new JWSBuilder().content(tokenBytes).rsa256(privateKey);
|
||||
|
||||
return accessTokenResponse(token, encodedToken);
|
||||
}
|
||||
|
@ -352,25 +435,25 @@ public class TokenService {
|
|||
@Path("login")
|
||||
@GET
|
||||
public Response loginPage(final @QueryParam("response_type") String responseType,
|
||||
final @QueryParam("redirect_uri") String redirect,
|
||||
final @QueryParam("client_id") String clientId,
|
||||
final @QueryParam("scope") String scopeParam,
|
||||
final @QueryParam("state") String state) {
|
||||
final @QueryParam("redirect_uri") String redirect, final @QueryParam("client_id") String clientId,
|
||||
final @QueryParam("scope") String scopeParam, final @QueryParam("state") String state) {
|
||||
return new Transaction() {
|
||||
protected Response callImpl() {
|
||||
OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
|
||||
|
||||
if (!realm.isEnabled()) {
|
||||
OAuthUtil.securityFailureForward(request, "Realm not enabled");
|
||||
oauth.forwardToSecurityFailure("Realm not enabled");
|
||||
return null;
|
||||
}
|
||||
UserModel client = realm.getUser(clientId);
|
||||
if (client == null) {
|
||||
OAuthUtil.securityFailureForward(request, "Unknown login requester.");
|
||||
oauth.forwardToSecurityFailure("Unknown login requester.");
|
||||
transaction.rollback();
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!client.isEnabled()) {
|
||||
OAuthUtil.securityFailureForward(request, "Login requester not enabled.");
|
||||
oauth.forwardToSecurityFailure("Login requester not enabled.");
|
||||
transaction.rollback();
|
||||
session.close();
|
||||
return null;
|
||||
|
@ -380,7 +463,7 @@ public class TokenService {
|
|||
RoleModel identityRequestRole = realm.getRole(RealmManager.IDENTITY_REQUESTER_ROLE);
|
||||
boolean isResource = realm.hasRole(client, resourceRole);
|
||||
if (!isResource && !realm.hasRole(client, identityRequestRole)) {
|
||||
OAuthUtil.securityFailureForward(request, "Login requester not allowed to request login.");
|
||||
oauth.forwardToSecurityFailure("Login requester not allowed to request login.");
|
||||
transaction.rollback();
|
||||
session.close();
|
||||
return null;
|
||||
|
@ -389,12 +472,42 @@ public class TokenService {
|
|||
UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
|
||||
if (user != null) {
|
||||
logger.info(user.getLoginName() + " already logged in.");
|
||||
return OAuthUtil.processAccessCode(realm, tokenManager, authManager, request, uriInfo, scopeParam, state,
|
||||
redirect, client, user);
|
||||
return oauth.processAccessCode(scopeParam, state, redirect, client, user);
|
||||
}
|
||||
|
||||
OAuthUtil.forwardToLoginForm(realm, request, uriInfo, redirect, clientId, scopeParam, state);
|
||||
return null;
|
||||
return Flows.forms(realm, request).forwardToLogin();
|
||||
}
|
||||
}.call();
|
||||
}
|
||||
|
||||
@Path("registrations")
|
||||
@GET
|
||||
public Response registerPage(final @QueryParam("response_type") String responseType,
|
||||
final @QueryParam("redirect_uri") String redirect, final @QueryParam("client_id") String clientId,
|
||||
final @QueryParam("scope") String scopeParam, final @QueryParam("state") String state) {
|
||||
return new Transaction() {
|
||||
protected Response callImpl() {
|
||||
OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
|
||||
|
||||
if (!realm.isEnabled()) {
|
||||
return oauth.forwardToSecurityFailure("Realm not enabled");
|
||||
}
|
||||
UserModel client = realm.getUser(clientId);
|
||||
if (client == null) {
|
||||
return oauth.forwardToSecurityFailure("Unknown login requester.");
|
||||
}
|
||||
|
||||
if (!client.isEnabled()) {
|
||||
return oauth.forwardToSecurityFailure("Login requester not enabled.");
|
||||
}
|
||||
|
||||
if (!realm.isRegistrationAllowed()) {
|
||||
return oauth.forwardToSecurityFailure("Registration not allowed");
|
||||
}
|
||||
|
||||
authManager.expireIdentityCookie(realm, uriInfo);
|
||||
|
||||
return Flows.forms(realm, request).forwardToRegistration();
|
||||
}
|
||||
}.call();
|
||||
}
|
||||
|
@ -425,6 +538,8 @@ public class TokenService {
|
|||
public Response processOAuth(final MultivaluedMap<String, String> formData) {
|
||||
return new Transaction() {
|
||||
protected Response callImpl() {
|
||||
OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
|
||||
|
||||
String code = formData.getFirst("code");
|
||||
JWSInput input = new JWSInput(code, providers);
|
||||
boolean verifiedCode = false;
|
||||
|
@ -434,16 +549,12 @@ public class TokenService {
|
|||
logger.debug("Failed to verify signature", ignored);
|
||||
}
|
||||
if (!verifiedCode) {
|
||||
OAuthUtil.securityFailureForward(request, "Illegal access code.");
|
||||
session.close();
|
||||
return null;
|
||||
return oauth.forwardToSecurityFailure("Illegal access code.");
|
||||
}
|
||||
String key = input.readContent(String.class);
|
||||
AccessCodeEntry accessCodeEntry = tokenManager.getAccessCode(key);
|
||||
if (accessCodeEntry == null) {
|
||||
OAuthUtil.securityFailureForward(request, "Unknown access code.");
|
||||
session.close();
|
||||
return null;
|
||||
return oauth.forwardToSecurityFailure("Unknown access code.");
|
||||
}
|
||||
|
||||
String redirect = accessCodeEntry.getRedirectUri();
|
||||
|
@ -453,16 +564,45 @@ public class TokenService {
|
|||
return redirectAccessDenied(redirect, state);
|
||||
}
|
||||
|
||||
return OAuthUtil.redirectAccessCode(realm, authManager, uriInfo, accessCodeEntry, state, redirect);
|
||||
return oauth.redirectAccessCode(accessCodeEntry, state, redirect);
|
||||
}
|
||||
}.call();
|
||||
}
|
||||
|
||||
protected Response redirectAccessDenied(String redirect, String state) {
|
||||
UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("error", "access_denied");
|
||||
if (state != null) redirectUri.queryParam("state", state);
|
||||
if (state != null)
|
||||
redirectUri.queryParam("state", state);
|
||||
Response.ResponseBuilder location = Response.status(302).location(redirectUri.build());
|
||||
return location.build();
|
||||
}
|
||||
|
||||
private String validateRegistrationForm(MultivaluedMap<String, String> formData) {
|
||||
if (isEmpty(formData.getFirst("name"))) {
|
||||
return "Please specify full name";
|
||||
}
|
||||
|
||||
if (isEmpty(formData.getFirst("email"))) {
|
||||
return "Please specify email";
|
||||
}
|
||||
|
||||
if (isEmpty(formData.getFirst("username"))) {
|
||||
return "Please specify username";
|
||||
}
|
||||
|
||||
if (isEmpty(formData.getFirst("password"))) {
|
||||
return "Please specify password";
|
||||
}
|
||||
|
||||
if (!formData.getFirst("password").equals(formData.getFirst("password-confirm"))) {
|
||||
return "Password confirmation doesn't match.";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isEmpty(String s) {
|
||||
return s == null || s.length() == 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
package org.keycloak.services.resources;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
public class Urls {
|
||||
|
||||
public static URI realmLoginAction(UriInfo uriInfo, String realmId) {
|
||||
return TokenService.processLoginUrl(uriInfo).build(realmId);
|
||||
}
|
||||
|
||||
public static URI realmLoginPage(UriInfo uriInfo, String realmId) {
|
||||
return uriInfo.getBaseUriBuilder().path(SaasService.class).path(SaasService.class, "processLogin").build();
|
||||
}
|
||||
|
||||
public static URI realmRegisterAction(UriInfo uriInfo, String realmId) {
|
||||
return URI.create("not-implemented-yet");
|
||||
}
|
||||
|
||||
public static URI realmRegisterPage(UriInfo uriInfo, String realmId) {
|
||||
return URI.create("not-implemented-yet");
|
||||
}
|
||||
|
||||
public static URI saasLoginAction(UriInfo uriInfo) {
|
||||
return uriInfo.getBaseUriBuilder().path(SaasService.class).path(SaasService.class, "processLogin").build();
|
||||
}
|
||||
|
||||
public static URI saasLoginPage(UriInfo uriInfo) {
|
||||
return uriInfo.getBaseUriBuilder().path(SaasService.class).path(SaasService.class, "loginPage").build();
|
||||
}
|
||||
|
||||
public static URI saasRegisterAction(UriInfo uriInfo) {
|
||||
return uriInfo.getBaseUriBuilder().path(SaasService.class).path(SaasService.class, "processRegister").build();
|
||||
}
|
||||
|
||||
public static URI saasRegisterPage(UriInfo uriInfo) {
|
||||
return uriInfo.getBaseUriBuilder().path(SaasService.class).path(SaasService.class, "registerPage").build();
|
||||
}
|
||||
|
||||
public static URI socialRedirectToProviderAuth(UriInfo uriInfo, String realmId) {
|
||||
return SocialResource.redirectToProviderAuthUrl(uriInfo).build(realmId);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package org.keycloak.services.resources.flows;
|
||||
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.jboss.resteasy.spi.HttpRequest;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
import org.keycloak.services.managers.TokenManager;
|
||||
import org.keycloak.services.models.RealmModel;
|
||||
|
||||
public class Flows {
|
||||
|
||||
private Flows() {
|
||||
}
|
||||
|
||||
public static PageFlows pages(HttpRequest request) {
|
||||
return new PageFlows(request);
|
||||
}
|
||||
|
||||
public static FormFlows forms(RealmModel realm, HttpRequest request) {
|
||||
return new FormFlows(realm, request);
|
||||
}
|
||||
|
||||
public static OAuthFlows oauth(RealmModel realm, HttpRequest request, UriInfo uriInfo, AuthenticationManager authManager,
|
||||
TokenManager tokenManager) {
|
||||
return new OAuthFlows(realm, request, uriInfo, authManager, tokenManager);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package org.keycloak.services.resources.flows;
|
||||
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.jboss.resteasy.spi.HttpRequest;
|
||||
import org.keycloak.services.models.RealmModel;
|
||||
import org.picketlink.idm.model.sample.Realm;
|
||||
|
||||
public class FormFlows {
|
||||
|
||||
public static final String REALM = Realm.class.getName();
|
||||
public static final String ERROR_MESSAGE = "KEYCLOAK_FORMS_ERROR_MESSAGE";
|
||||
public static final String DATA = "KEYCLOAK_FORMS_DATA";
|
||||
|
||||
private MultivaluedMap<String, String> formData;
|
||||
private String error;
|
||||
|
||||
private RealmModel realm;
|
||||
|
||||
private HttpRequest request;
|
||||
|
||||
FormFlows(RealmModel realm, HttpRequest request) {
|
||||
this.realm = realm;
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
public FormFlows setFormData(MultivaluedMap<String, String> formData) {
|
||||
this.formData = formData;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FormFlows setError(String error) {
|
||||
this.error = error;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Response forwardToLogin() {
|
||||
return forwardToForm(Pages.LOGIN);
|
||||
}
|
||||
|
||||
public Response forwardToRegistration() {
|
||||
return forwardToForm(Pages.REGISTER);
|
||||
}
|
||||
|
||||
private Response forwardToForm(String form) {
|
||||
request.setAttribute(REALM, realm);
|
||||
|
||||
if (error != null) {
|
||||
request.setAttribute(ERROR_MESSAGE, error);
|
||||
}
|
||||
|
||||
if (formData != null) {
|
||||
request.setAttribute(DATA, formData);
|
||||
}
|
||||
|
||||
request.forward(form);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package org.keycloak.services.resources.flows;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.jboss.resteasy.logging.Logger;
|
||||
import org.jboss.resteasy.spi.HttpRequest;
|
||||
import org.keycloak.services.managers.AccessCodeEntry;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.managers.TokenManager;
|
||||
import org.keycloak.services.models.RealmModel;
|
||||
import org.keycloak.services.models.RoleModel;
|
||||
import org.keycloak.services.models.UserModel;
|
||||
import org.keycloak.services.resources.TokenService;
|
||||
|
||||
public class OAuthFlows {
|
||||
|
||||
private static final Logger log = Logger.getLogger(OAuthFlows.class);
|
||||
|
||||
private RealmModel realm;
|
||||
|
||||
private HttpRequest request;
|
||||
|
||||
private UriInfo uriInfo;
|
||||
|
||||
private AuthenticationManager authManager;
|
||||
|
||||
private TokenManager tokenManager;
|
||||
|
||||
OAuthFlows(RealmModel realm, HttpRequest request, UriInfo uriInfo, AuthenticationManager authManager,
|
||||
TokenManager tokenManager) {
|
||||
this.realm = realm;
|
||||
this.request = request;
|
||||
this.uriInfo = uriInfo;
|
||||
this.authManager = authManager;
|
||||
this.tokenManager = tokenManager;
|
||||
}
|
||||
|
||||
public Response redirectAccessCode(AccessCodeEntry accessCode, String state, String redirect) {
|
||||
String code = accessCode.getCode();
|
||||
UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("code", code);
|
||||
log.info("redirectAccessCode: state: " + state);
|
||||
if (state != null)
|
||||
redirectUri.queryParam("state", state);
|
||||
Response.ResponseBuilder location = Response.status(302).location(redirectUri.build());
|
||||
if (realm.isCookieLoginAllowed()) {
|
||||
location.cookie(authManager.createLoginCookie(realm, accessCode.getUser(), uriInfo));
|
||||
}
|
||||
return location.build();
|
||||
}
|
||||
|
||||
public Response processAccessCode(String scopeParam, String state, String redirect, UserModel client, UserModel user) {
|
||||
RoleModel resourceRole = realm.getRole(RealmManager.RESOURCE_ROLE);
|
||||
RoleModel identityRequestRole = realm.getRole(RealmManager.IDENTITY_REQUESTER_ROLE);
|
||||
boolean isResource = realm.hasRole(client, resourceRole);
|
||||
if (!isResource && !realm.hasRole(client, identityRequestRole)) {
|
||||
return forwardToSecurityFailure("Login requester not allowed to request login.");
|
||||
}
|
||||
AccessCodeEntry accessCode = tokenManager.createAccessCode(scopeParam, state, redirect, realm, client, user);
|
||||
log.info("processAccessCode: isResource: " + isResource);
|
||||
log.info("processAccessCode: go to oauth page?: "
|
||||
+ (!isResource && (accessCode.getRealmRolesRequested().size() > 0 || accessCode.getResourceRolesRequested()
|
||||
.size() > 0)));
|
||||
if (!isResource
|
||||
&& (accessCode.getRealmRolesRequested().size() > 0 || accessCode.getResourceRolesRequested().size() > 0)) {
|
||||
return oauthGrantPage(accessCode, client);
|
||||
}
|
||||
|
||||
return redirectAccessCode(accessCode, state, redirect);
|
||||
}
|
||||
|
||||
public Response oauthGrantPage(AccessCodeEntry accessCode, UserModel client) {
|
||||
request.setAttribute("realmRolesRequested", accessCode.getRealmRolesRequested());
|
||||
request.setAttribute("resourceRolesRequested", accessCode.getResourceRolesRequested());
|
||||
request.setAttribute("client", client);
|
||||
request.setAttribute("action", TokenService.processOAuthUrl(uriInfo).build(realm.getId()).toString());
|
||||
request.setAttribute("code", accessCode.getCode());
|
||||
|
||||
request.forward(Pages.OAUTH_GRANT);
|
||||
return null;
|
||||
}
|
||||
|
||||
public Response forwardToSecurityFailure(String message) {
|
||||
return Flows.pages(request).forwardToSecurityFailure(message);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package org.keycloak.services.resources.flows;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.jboss.resteasy.logging.Logger;
|
||||
import org.jboss.resteasy.spi.HttpRequest;
|
||||
import org.keycloak.services.JspRequestParameters;
|
||||
|
||||
public class PageFlows {
|
||||
|
||||
private static final Logger log = Logger.getLogger(PageFlows.class);
|
||||
|
||||
private HttpRequest request;
|
||||
|
||||
PageFlows(HttpRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
public Response forwardToSecurityFailure(String message) {
|
||||
log.error(message);
|
||||
|
||||
request.setAttribute(JspRequestParameters.KEYCLOAK_SECURITY_FAILURE_MESSAGE, message);
|
||||
|
||||
request.forward(Pages.SECURITY_FAILURE);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package org.keycloak.services.resources.flows;
|
||||
|
||||
public class Pages {
|
||||
|
||||
public final static String LOGIN = "/sdk/login.xhtml";
|
||||
|
||||
public final static String OAUTH_GRANT = "/saas/oauthGrantForm.jsp";
|
||||
|
||||
public final static String REGISTER = "/sdk/register.xhtml";
|
||||
|
||||
public final static String SECURITY_FAILURE = "/saas/securityFailure.jsp";
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package org.keycloak.services.resources.flows;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
|
||||
import org.keycloak.services.resources.RealmsResource;
|
||||
import org.keycloak.services.resources.SaasService;
|
||||
import org.keycloak.services.resources.SocialResource;
|
||||
import org.keycloak.services.resources.TokenService;
|
||||
|
||||
public class Urls {
|
||||
|
||||
private static UriBuilder realmBase(URI baseUri) {
|
||||
return UriBuilder.fromUri(baseUri).path(RealmsResource.class);
|
||||
}
|
||||
|
||||
private static UriBuilder tokenBase(URI baseUri) {
|
||||
return realmBase(baseUri).path(RealmsResource.class, "getTokenService");
|
||||
}
|
||||
|
||||
public static URI realmLoginAction(URI baseUri, String realmId) {
|
||||
return tokenBase(baseUri).path(TokenService.class, "processLogin").build(realmId);
|
||||
}
|
||||
|
||||
public static URI realmLoginPage(URI baseUri, String realmId) {
|
||||
return tokenBase(baseUri).path(TokenService.class, "loginPage").build(realmId);
|
||||
}
|
||||
|
||||
public static URI realmRegisterAction(URI baseUri, String realmId) {
|
||||
return tokenBase(baseUri).path(TokenService.class, "processRegister").build(realmId);
|
||||
}
|
||||
|
||||
public static URI realmRegisterPage(URI baseUri, String realmId) {
|
||||
return tokenBase(baseUri).path(TokenService.class, "registerPage").build(realmId);
|
||||
}
|
||||
|
||||
private static UriBuilder saasBase(URI baseUri) {
|
||||
return UriBuilder.fromUri(baseUri).path(SaasService.class);
|
||||
}
|
||||
|
||||
public static URI saasLoginAction(URI baseUri) {
|
||||
return saasBase(baseUri).path(SaasService.class, "processLogin").build();
|
||||
}
|
||||
|
||||
public static URI saasLoginPage(URI baseUri) {
|
||||
return saasBase(baseUri).path(SaasService.class, "loginPage").build();
|
||||
}
|
||||
|
||||
public static URI saasRegisterAction(URI baseUri) {
|
||||
return saasBase(baseUri).path(SaasService.class, "processRegister").build();
|
||||
}
|
||||
|
||||
public static URI saasRegisterPage(URI baseUri) {
|
||||
return saasBase(baseUri).path(SaasService.class, "registerPage").build();
|
||||
}
|
||||
|
||||
private static UriBuilder socialBase(URI baseUri) {
|
||||
return UriBuilder.fromUri(baseUri).path(SocialResource.class);
|
||||
}
|
||||
|
||||
public static URI socialCallback(URI baseUri) {
|
||||
return socialBase(baseUri).path(SocialResource.class, "callback").build();
|
||||
}
|
||||
|
||||
public static URI socialRedirectToProviderAuth(URI baseUri, String realmId) {
|
||||
return socialBase(baseUri).path(SocialResource.class, "redirectToProviderAuth")
|
||||
.build(realmId);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue