Started support for installed applications
This commit is contained in:
parent
ec309e7e02
commit
87aaaf0b06
13 changed files with 171 additions and 99 deletions
19
forms/common-themes/src/main/resources/theme/login/base/code.ftl
Executable file
19
forms/common-themes/src/main/resources/theme/login/base/code.ftl
Executable file
|
@ -0,0 +1,19 @@
|
|||
<#import "template.ftl" as layout>
|
||||
<@layout.registrationLayout; section>
|
||||
<#if section = "title">
|
||||
<#if code.success>
|
||||
Success code=${code.code}
|
||||
<#else>
|
||||
Error error=${code.error}
|
||||
</#if>
|
||||
<#elseif section = "form">
|
||||
<div id="kc-code">
|
||||
<#if code.success>
|
||||
<p>Please copy this code and paste it into your application:</p>
|
||||
<textarea id="code">${code.code}</textarea>
|
||||
<#else>
|
||||
<p>${code.error}</p>
|
||||
</#if>
|
||||
</div>
|
||||
</#if>
|
||||
</@layout.registrationLayout>
|
|
@ -1,33 +0,0 @@
|
|||
<#import "template.ftl" as layout>
|
||||
<@layout.registrationLayout displayInfo=true; section>
|
||||
<#if section = "title">
|
||||
${rb.emailUsernameForgotHeader}
|
||||
<#elseif section = "header">
|
||||
${rb.emailUsernameForgotHeader}
|
||||
<#elseif section = "form">
|
||||
<form id="kc-username-reminder-form" class="${properties.kcFormClass!}" action="${url.loginUsernameReminderUrl}" method="post">
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div class="${properties.kcLabelWrapperClass!}">
|
||||
<label for="email" class="${properties.kcLabelClass!}">${rb.email}</label>
|
||||
</div>
|
||||
<div class="${properties.kcInputWrapperClass!}">
|
||||
<input type="text" id="email" name="email" class="${properties.kcInputClass!}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
|
||||
<div class="${properties.kcFormOptionsWrapperClass!}">
|
||||
<span><a href="${url.loginUrl}">${rb.backToLogin}</a></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
|
||||
<input class="btn btn-primary btn-lg" type="submit" value="${rb.submit}"/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<#elseif section = "info" >
|
||||
${rb.emailUsernameInstruction}
|
||||
</#if>
|
||||
</@layout.registrationLayout>
|
|
@ -121,6 +121,12 @@ ol#kc-totp-settings li:first-of-type {
|
|||
width: 50%;
|
||||
}
|
||||
|
||||
/* Code */
|
||||
#kc-code textarea {
|
||||
width: 100%;
|
||||
height: 8em;
|
||||
}
|
||||
|
||||
/* Social */
|
||||
|
||||
#kc-social-providers ul {
|
||||
|
|
|
@ -27,6 +27,8 @@ public interface LoginForms {
|
|||
|
||||
public Response createOAuthGrant();
|
||||
|
||||
public Response createCode();
|
||||
|
||||
public LoginForms setAccessCode(String accessCodeId, String accessCode);
|
||||
|
||||
public LoginForms setAccessRequest(List<RoleModel> realmRolesRequested, MultivaluedMap<String,RoleModel> resourceRolesRequested);
|
||||
|
|
|
@ -5,6 +5,6 @@ package org.keycloak.login;
|
|||
*/
|
||||
public enum LoginFormsPages {
|
||||
|
||||
LOGIN, LOGIN_TOTP, LOGIN_CONFIG_TOTP, LOGIN_VERIFY_EMAIL, OAUTH_GRANT, LOGIN_RESET_PASSWORD, LOGIN_UPDATE_PASSWORD, LOGIN_USERNAME_REMINDER, REGISTER, ERROR, LOGIN_UPDATE_PROFILE;
|
||||
LOGIN, LOGIN_TOTP, LOGIN_CONFIG_TOTP, LOGIN_VERIFY_EMAIL, OAUTH_GRANT, LOGIN_RESET_PASSWORD, LOGIN_UPDATE_PASSWORD, REGISTER, ERROR, LOGIN_UPDATE_PROFILE, CODE;
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import org.keycloak.freemarker.Theme;
|
|||
import org.keycloak.freemarker.ThemeLoader;
|
||||
import org.keycloak.login.LoginForms;
|
||||
import org.keycloak.login.LoginFormsPages;
|
||||
import org.keycloak.login.freemarker.model.CodeBean;
|
||||
import org.keycloak.login.freemarker.model.LoginBean;
|
||||
import org.keycloak.login.freemarker.model.MessageBean;
|
||||
import org.keycloak.login.freemarker.model.OAuthGrantBean;
|
||||
|
@ -178,6 +179,9 @@ public class FreeMarkerLoginForms implements LoginForms {
|
|||
case OAUTH_GRANT:
|
||||
attributes.put("oauth", new OAuthGrantBean(accessCode, client, realmRolesRequested, resourceRolesRequested));
|
||||
break;
|
||||
case CODE:
|
||||
attributes.put("code", new CodeBean(accessCode, messageType == MessageType.ERROR ? message : null));
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -197,10 +201,6 @@ public class FreeMarkerLoginForms implements LoginForms {
|
|||
return createResponse(LoginFormsPages.LOGIN_RESET_PASSWORD);
|
||||
}
|
||||
|
||||
public Response createUsernameReminder() {
|
||||
return createResponse(LoginFormsPages.LOGIN_USERNAME_REMINDER);
|
||||
}
|
||||
|
||||
public Response createLoginTotp() {
|
||||
return createResponse(LoginFormsPages.LOGIN_TOTP);
|
||||
}
|
||||
|
@ -218,6 +218,11 @@ public class FreeMarkerLoginForms implements LoginForms {
|
|||
return createResponse(LoginFormsPages.OAUTH_GRANT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response createCode() {
|
||||
return createResponse(LoginFormsPages.CODE);
|
||||
}
|
||||
|
||||
public FreeMarkerLoginForms setError(String message) {
|
||||
this.message = message;
|
||||
this.messageType = MessageType.ERROR;
|
||||
|
|
|
@ -29,6 +29,8 @@ public class Templates {
|
|||
return "error.ftl";
|
||||
case LOGIN_UPDATE_PROFILE:
|
||||
return "login-update-profile.ftl";
|
||||
case CODE:
|
||||
return "code.ftl";
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package org.keycloak.login.freemarker.model;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class CodeBean {
|
||||
|
||||
private final String code;
|
||||
private final String error;
|
||||
|
||||
public CodeBean(String code, String error) {
|
||||
this.code = code;
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return code != null && error == null;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ var Keycloak = function (options) {
|
|||
return new Keycloak(options);
|
||||
}
|
||||
|
||||
var instance = this;
|
||||
var kc = this;
|
||||
|
||||
if (!options.url) {
|
||||
var scripts = document.getElementsByTagName('script');
|
||||
|
@ -33,7 +33,7 @@ var Keycloak = function (options) {
|
|||
throw 'clientSecret missing';
|
||||
}
|
||||
|
||||
this.init = function (successCallback, errorCallback) {
|
||||
kc.init = function (successCallback, errorCallback) {
|
||||
if (window.oauth.callback) {
|
||||
delete sessionStorage.oauthToken;
|
||||
processCallback(successCallback, errorCallback);
|
||||
|
@ -44,50 +44,50 @@ var Keycloak = function (options) {
|
|||
} else if (options.onload) {
|
||||
switch (options.onload) {
|
||||
case 'login-required' :
|
||||
window.location = createLoginUrl(true);
|
||||
window.location = kc.createLoginUrl(true);
|
||||
break;
|
||||
case 'check-sso' :
|
||||
window.location = createLoginUrl(false);
|
||||
window.location = kc.createLoginUrl(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.login = function () {
|
||||
window.location.href = createLoginUrl(true);
|
||||
kc.login = function () {
|
||||
window.location.href = kc.createLoginUrl(true);
|
||||
}
|
||||
|
||||
this.logout = function () {
|
||||
kc.logout = function () {
|
||||
setToken(undefined);
|
||||
window.location.href = createLogoutUrl();
|
||||
window.location.href = kc.createLogoutUrl();
|
||||
}
|
||||
|
||||
this.hasRealmRole = function (role) {
|
||||
var access = this.realmAccess;
|
||||
kc.hasRealmRole = function (role) {
|
||||
var access = kc.realmAccess;
|
||||
return access && access.roles.indexOf(role) >= 0 || false;
|
||||
}
|
||||
|
||||
this.hasResourceRole = function (role, resource) {
|
||||
if (!this.resourceAccess) {
|
||||
kc.hasResourceRole = function (role, resource) {
|
||||
if (!kc.resourceAccess) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var access = this.resourceAccess[resource || options.clientId];
|
||||
var access = kc.resourceAccess[resource || options.clientId];
|
||||
return access && access.roles.indexOf(role) >= 0 || false;
|
||||
}
|
||||
|
||||
this.loadUserProfile = function (success, error) {
|
||||
var url = getRealmUrl() + '/account';
|
||||
kc.loadUserProfile = function (success, error) {
|
||||
var url = kc.getRealmUrl() + '/account';
|
||||
var req = new XMLHttpRequest();
|
||||
req.open('GET', url, true);
|
||||
req.setRequestHeader('Accept', 'application/json');
|
||||
req.setRequestHeader('Authorization', 'bearer ' + this.token);
|
||||
req.setRequestHeader('Authorization', 'bearer ' + kc.token);
|
||||
|
||||
req.onreadystatechange = function () {
|
||||
if (req.readyState == 4) {
|
||||
if (req.status == 200) {
|
||||
instance.profile = JSON.parse(req.responseText);
|
||||
success && success(instance.profile)
|
||||
kc.profile = JSON.parse(req.responseText);
|
||||
success && success(kc.profile)
|
||||
} else {
|
||||
var response = { status: req.status, statusText: req.status };
|
||||
if (req.responseText) {
|
||||
|
@ -108,22 +108,22 @@ var Keycloak = function (options) {
|
|||
* @param successCallback
|
||||
* @param errorCallback
|
||||
*/
|
||||
this.onValidAccessToken = function(successCallback, errorCallback) {
|
||||
if (!this.tokenParsed) {
|
||||
kc.onValidAccessToken = function(successCallback, errorCallback) {
|
||||
if (!kc.tokenParsed) {
|
||||
console.log('no token');
|
||||
errorCallback();
|
||||
return;
|
||||
}
|
||||
var currTime = new Date().getTime() / 1000;
|
||||
if (currTime > this.tokenParsed['exp']) {
|
||||
if (!this.refreshToken) {
|
||||
if (currTime > kc.tokenParsed['exp']) {
|
||||
if (!kc.refreshToken) {
|
||||
console.log('no refresh token');
|
||||
errorCallback();
|
||||
return;
|
||||
}
|
||||
console.log('calling refresh');
|
||||
var params = 'grant_type=refresh_token&' + 'refresh_token=' + this.refreshToken;
|
||||
var url = getRealmUrl() + '/tokens/refresh';
|
||||
var params = 'grant_type=refresh_token&' + 'refresh_token=' + kc.refreshToken;
|
||||
var url = kc.getRealmUrl() + '/tokens/refresh';
|
||||
|
||||
var req = new XMLHttpRequest();
|
||||
req.open('POST', url, true, options.clientId, options.clientSecret);
|
||||
|
@ -134,8 +134,8 @@ var Keycloak = function (options) {
|
|||
if (req.status == 200) {
|
||||
console.log('Refresh Success');
|
||||
var tokenResponse = JSON.parse(req.responseText);
|
||||
this.refreshToken = tokenResponse['refresh_token'];
|
||||
setToken(tokenResponse['access_token'], successCallback);
|
||||
kc.refreshToken = tokenResponse['refresh_token'];
|
||||
kc.setToken(tokenResponse['access_token'], successCallback);
|
||||
} else {
|
||||
console.log('error on refresh HTTP invoke: ' + req.status);
|
||||
errorCallback && errorCallback({ authenticated: false, status: req.status, statusText: req.statusText });
|
||||
|
@ -150,7 +150,7 @@ var Keycloak = function (options) {
|
|||
|
||||
}
|
||||
|
||||
function getRealmUrl() {
|
||||
kc.getRealmUrl = function() {
|
||||
return options.url + '/auth/rest/realms/' + encodeURIComponent(options.realm);
|
||||
}
|
||||
|
||||
|
@ -161,7 +161,7 @@ var Keycloak = function (options) {
|
|||
|
||||
if (code) {
|
||||
var params = 'code=' + code;
|
||||
var url = getRealmUrl() + '/tokens/access/codes';
|
||||
var url = kc.getRealmUrl() + '/tokens/access/codes';
|
||||
|
||||
var req = new XMLHttpRequest();
|
||||
req.open('POST', url, true, options.clientId, options.clientSecret);
|
||||
|
@ -171,8 +171,8 @@ var Keycloak = function (options) {
|
|||
if (req.readyState == 4) {
|
||||
if (req.status == 200) {
|
||||
var tokenResponse = JSON.parse(req.responseText);
|
||||
instance.refreshToken = tokenResponse['refresh_token'];
|
||||
setToken(tokenResponse['access_token'], successCallback);
|
||||
kc.refreshToken = tokenResponse['refresh_token'];
|
||||
kc.setToken(tokenResponse['access_token'], successCallback);
|
||||
} else {
|
||||
errorCallback && errorCallback({ authenticated: false, status: req.status, statusText: req.statusText });
|
||||
}
|
||||
|
@ -189,33 +189,33 @@ var Keycloak = function (options) {
|
|||
}
|
||||
}
|
||||
|
||||
function setToken(token, successCallback) {
|
||||
kc.setToken = function(token, successCallback) {
|
||||
if (token) {
|
||||
sessionStorage.oauthToken = token;
|
||||
window.oauth.token = token;
|
||||
instance.token = token;
|
||||
kc.token = token;
|
||||
|
||||
instance.tokenParsed = JSON.parse(atob(token.split('.')[1]));
|
||||
instance.authenticated = true;
|
||||
instance.username = instance.tokenParsed.sub;
|
||||
instance.realmAccess = instance.tokenParsed.realm_access;
|
||||
instance.resourceAccess = instance.tokenParsed.resource_access;
|
||||
kc.tokenParsed = JSON.parse(atob(token.split('.')[1]));
|
||||
kc.authenticated = true;
|
||||
kc.username = kc.tokenParsed.sub;
|
||||
kc.realmAccess = kc.tokenParsed.realm_access;
|
||||
kc.resourceAccess = kc.tokenParsed.resource_access;
|
||||
|
||||
setTimeout(function() {
|
||||
successCallback && successCallback({ authenticated: instance.authenticated, username: instance.username });
|
||||
successCallback && successCallback({ authenticated: kc.authenticated, username: kc.username });
|
||||
}, 0);
|
||||
} else {
|
||||
delete sessionStorage.oauthToken;
|
||||
delete window.oauth.token;
|
||||
delete instance.token;
|
||||
delete kc.token;
|
||||
}
|
||||
}
|
||||
|
||||
function createLoginUrl(prompt) {
|
||||
kc.createLoginUrl = function(prompt) {
|
||||
var state = createUUID();
|
||||
|
||||
sessionStorage.oauthState = state;
|
||||
var url = getRealmUrl()
|
||||
var url = kc.getRealmUrl()
|
||||
+ '/tokens/login'
|
||||
+ '?client_id=' + encodeURIComponent(options.clientId)
|
||||
+ '&redirect_uri=' + getEncodedRedirectUri()
|
||||
|
@ -229,17 +229,22 @@ var Keycloak = function (options) {
|
|||
return url;
|
||||
}
|
||||
|
||||
function createLogoutUrl() {
|
||||
var url = getRealmUrl()
|
||||
kc.createLogoutUrl = function() {
|
||||
var url = kc.getRealmUrl()
|
||||
+ '/tokens/logout'
|
||||
+ '?redirect_uri=' + getEncodedRedirectUri();
|
||||
return url;
|
||||
}
|
||||
|
||||
function getEncodedRedirectUri() {
|
||||
var url = (location.protocol + '//' + location.hostname + (location.port && (':' + location.port)) + location.pathname);
|
||||
if (location.hash) {
|
||||
url += '?redirect_fragment=' + encodeURIComponent(location.hash.substring(1));
|
||||
var url;
|
||||
if (options.redirectUri) {
|
||||
url = options.redirectUri;
|
||||
} else {
|
||||
url = (location.protocol + '//' + location.hostname + (location.port && (':' + location.port)) + location.pathname);
|
||||
if (location.hash) {
|
||||
url += '?redirect_fragment=' + encodeURIComponent(location.hash.substring(1));
|
||||
}
|
||||
}
|
||||
return encodeURI(url);
|
||||
}
|
||||
|
|
|
@ -11,4 +11,6 @@ public interface Constants {
|
|||
String INTERNAL_ROLE = "KEYCLOAK_";
|
||||
|
||||
String ACCOUNT_MANAGEMENT_APP = "account";
|
||||
|
||||
String INSTALLED_APP_URN = "urn:ietf:wg:oauth:2.0:oob";
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.keycloak.services.managers.AuthenticationManager;
|
|||
import org.keycloak.services.managers.TokenManager;
|
||||
import org.keycloak.services.resources.TokenService;
|
||||
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.core.Cookie;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
|
@ -79,24 +80,32 @@ public class OAuthFlows {
|
|||
|
||||
public Response redirectAccessCode(AccessCodeEntry accessCode, String state, String redirect, boolean rememberMe) {
|
||||
String code = accessCode.getCode();
|
||||
UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("code", code);
|
||||
log.debug("redirectAccessCode: state: {0}", state);
|
||||
if (state != null)
|
||||
redirectUri.queryParam("state", state);
|
||||
Response.ResponseBuilder location = Response.status(302).location(redirectUri.build());
|
||||
Cookie remember = request.getHttpHeaders().getCookies().get(AuthenticationManager.KEYCLOAK_REMEMBER_ME);
|
||||
rememberMe = rememberMe || remember != null;
|
||||
location.cookie(authManager.createLoginCookie(realm, accessCode.getUser(), uriInfo, rememberMe));
|
||||
return location.build();
|
||||
|
||||
if (Constants.INSTALLED_APP_URN.equals(redirect)) {
|
||||
return Flows.forms(realm, request, uriInfo).setAccessCode(accessCode.getId(), code).createCode();
|
||||
} else {
|
||||
UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("code", code);
|
||||
log.debug("redirectAccessCode: state: {0}", state);
|
||||
if (state != null)
|
||||
redirectUri.queryParam("state", state);
|
||||
Response.ResponseBuilder location = Response.status(302).location(redirectUri.build());
|
||||
Cookie remember = request.getHttpHeaders().getCookies().get(AuthenticationManager.KEYCLOAK_REMEMBER_ME);
|
||||
rememberMe = rememberMe || remember != null;
|
||||
location.cookie(authManager.createLoginCookie(realm, accessCode.getUser(), uriInfo, rememberMe));
|
||||
return location.build();
|
||||
}
|
||||
}
|
||||
|
||||
public Response redirectError(ClientModel client, String error, String state, String redirect) {
|
||||
UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("error", error);
|
||||
if (state != null) {
|
||||
redirectUri.queryParam("state", state);
|
||||
if (Constants.INSTALLED_APP_URN.equals(redirect)) {
|
||||
return Flows.forms(realm, request, uriInfo).setError(error).createCode();
|
||||
} else {
|
||||
UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("error", error);
|
||||
if (state != null) {
|
||||
redirectUri.queryParam("state", state);
|
||||
}
|
||||
return Response.status(302).location(redirectUri.build()).build();
|
||||
}
|
||||
|
||||
return Response.status(302).location(redirectUri.build()).build();
|
||||
}
|
||||
|
||||
public Response processAccessCode(String scopeParam, String state, String redirect, ClientModel client, UserModel user) {
|
||||
|
|
|
@ -38,6 +38,8 @@ import org.json.JSONObject;
|
|||
import org.junit.Assert;
|
||||
import org.keycloak.RSATokenVerifier;
|
||||
import org.keycloak.VerificationException;
|
||||
import org.keycloak.jose.jws.JWSInput;
|
||||
import org.keycloak.jose.jws.crypto.RSAProvider;
|
||||
import org.keycloak.representations.AccessScope;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
|
@ -156,6 +158,12 @@ public class OAuthClient {
|
|||
}
|
||||
}
|
||||
|
||||
public void verifyCode(String code) {
|
||||
if (!RSAProvider.verify(new JWSInput(code), realmPublicKey)) {
|
||||
throw new RuntimeException("Failed to verify code");
|
||||
}
|
||||
}
|
||||
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
|
|
@ -26,8 +26,8 @@ import org.junit.ClassRule;
|
|||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.testsuite.OAuthClient;
|
||||
import org.keycloak.testsuite.OAuthClient.AuthorizationCodeResponse;
|
||||
|
@ -36,6 +36,7 @@ import org.keycloak.testsuite.pages.LoginPage;
|
|||
import org.keycloak.testsuite.rule.KeycloakRule;
|
||||
import org.keycloak.testsuite.rule.WebResource;
|
||||
import org.keycloak.testsuite.rule.WebRule;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -73,6 +74,21 @@ public class AuthorizationCodeTest {
|
|||
Assert.assertNotNull(response.getCode());
|
||||
Assert.assertEquals("mystate", response.getState());
|
||||
Assert.assertNull(response.getError());
|
||||
|
||||
oauth.verifyCode(response.getCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorizationRequestInstalledApp() throws IOException {
|
||||
oauth.redirectUri(Constants.INSTALLED_APP_URN);
|
||||
|
||||
oauth.doLogin("test-user@localhost", "password");
|
||||
|
||||
String title = driver.getTitle();
|
||||
Assert.assertTrue(title.startsWith("Success code="));
|
||||
|
||||
String code = driver.findElement(By.id("code")).getText();
|
||||
oauth.verifyCode(code);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -94,6 +110,8 @@ public class AuthorizationCodeTest {
|
|||
|
||||
Assert.assertTrue(response.isRedirected());
|
||||
Assert.assertNotNull(response.getCode());
|
||||
|
||||
oauth.verifyCode(response.getCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -104,6 +122,8 @@ public class AuthorizationCodeTest {
|
|||
Assert.assertNotNull(response.getCode());
|
||||
Assert.assertNull(response.getState());
|
||||
Assert.assertNull(response.getError());
|
||||
|
||||
oauth.verifyCode(response.getCode());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue