Added realm registration

This commit is contained in:
Stian Thorgersen 2013-08-15 11:31:10 +01:00
parent 0ffe1cb354
commit 92235e3b07
17 changed files with 560 additions and 329 deletions

View file

@ -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" ],

View file

@ -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 {

View file

@ -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);
}

View file

@ -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);
}
}

View file

@ -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";
}

View file

@ -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();

View file

@ -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");
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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";
}

View file

@ -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);
}
}