Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
e48cc006f6
41 changed files with 370 additions and 130 deletions
|
@ -6,6 +6,7 @@ package org.keycloak.representations.idm;
|
|||
public class SocialLinkRepresentation {
|
||||
|
||||
protected String socialProvider;
|
||||
protected String socialUserId;
|
||||
protected String socialUsername;
|
||||
|
||||
public String getSocialProvider() {
|
||||
|
@ -16,6 +17,14 @@ public class SocialLinkRepresentation {
|
|||
this.socialProvider = socialProvider;
|
||||
}
|
||||
|
||||
public String getSocialUserId() {
|
||||
return socialUserId;
|
||||
}
|
||||
|
||||
public void setSocialUserId(String socialUserId) {
|
||||
this.socialUserId = socialUserId;
|
||||
}
|
||||
|
||||
public String getSocialUsername() {
|
||||
return socialUsername;
|
||||
}
|
||||
|
|
|
@ -32,9 +32,10 @@ public class SocialMappingRepresentation {
|
|||
return socialLinks;
|
||||
}
|
||||
|
||||
public SocialLinkRepresentation socialLink(String socialProvider, String socialUsername) {
|
||||
public SocialLinkRepresentation socialLink(String socialProvider, String socialUserId, String socialUsername) {
|
||||
SocialLinkRepresentation link = new SocialLinkRepresentation();
|
||||
link.setSocialProvider(socialProvider);
|
||||
link.setSocialUserId(socialUserId);
|
||||
link.setSocialUsername(socialUsername);
|
||||
if (socialLinks == null) socialLinks = new ArrayList<SocialLinkRepresentation>();
|
||||
socialLinks.add(link);
|
||||
|
|
|
@ -40,10 +40,4 @@
|
|||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<tip>
|
||||
<para>
|
||||
Facebook doesn't allow <literal>localhost</literal> in the redirect URI. To test on a local server
|
||||
replace <literal>localhost</literal> with <literal>127.0.0.1</literal>.
|
||||
</para>
|
||||
</tip>
|
||||
</section>
|
|
@ -1,25 +1,52 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Customer View Page</title>
|
||||
<script src="/auth/js/keycloak.js"></script>
|
||||
<script src="http://localhost:8081/auth/js/keycloak.js"></script>
|
||||
</head>
|
||||
<body bgcolor="#E3F6CE">
|
||||
|
||||
<p>Goto: <a href="#" onclick="keycloak.logout()">logout</a></p>
|
||||
User <b id="username"></b> made this request.
|
||||
User <b id="subject"></b> made this request.
|
||||
<p><b>User details (from <span id="profileType"></span>)</b></p>
|
||||
<p>Username: <span id="username"></span></p>
|
||||
<p>Email: <span id="email"></span></p>
|
||||
<p>Full Name: <span id="name"></span></p>
|
||||
<p>First: <span id="givenName"></span></p>
|
||||
<p>Last: <span id="familyName"></span></p>
|
||||
|
||||
<h2>Customer Listing</h2>
|
||||
<div id="customers"></div>
|
||||
|
||||
<script>
|
||||
var keycloak = Keycloak({
|
||||
clientId: 'customer-portal',
|
||||
clientSecret: 'password',
|
||||
realm: 'demo',
|
||||
onload: 'login-required'
|
||||
});
|
||||
|
||||
var loadData = function () {
|
||||
document.getElementById('username').innerText = keycloak.username;
|
||||
document.getElementById('subject').innerText = keycloak.subject;
|
||||
|
||||
console.debug(keycloak.idToken);
|
||||
if (keycloak.idToken) {
|
||||
document.getElementById('profileType').innerText = 'IDToken';
|
||||
document.getElementById('username').innerText = keycloak.idToken.preferred_username;
|
||||
document.getElementById('email').innerText = keycloak.idToken.email;
|
||||
document.getElementById('name').innerText = keycloak.idToken.name;
|
||||
document.getElementById('givenName').innerText = keycloak.idToken.given_name;
|
||||
document.getElementById('familyName').innerText = keycloak.idToken.family_name;
|
||||
} else {
|
||||
keycloak.loadUserProfile(function() {
|
||||
document.getElementById('profileType').innerText = 'Account Service';
|
||||
document.getElementById('username').innerText = keycloak.profile.username;
|
||||
document.getElementById('email').innerText = keycloak.profile.email;
|
||||
document.getElementById('name').innerText = keycloak.profile.firstName + ' ' + keycloak.profile.lastName;
|
||||
document.getElementById('givenName').innerText = keycloak.profile.firstName;
|
||||
document.getElementById('familyName').innerText = keycloak.profile.lastName;
|
||||
}, function() {
|
||||
document.getElementById('profileType').innerText = 'Failed to retrieve user details. Please enable claims or account role';
|
||||
});
|
||||
}
|
||||
|
||||
var url = 'http://localhost:8080/database/customers';
|
||||
|
||||
|
@ -50,12 +77,11 @@ User <b id="username"></b> made this request.
|
|||
|
||||
};
|
||||
|
||||
|
||||
|
||||
var reloadData = function () {
|
||||
keycloak.onValidAccessToken(loadData, loadFailure);
|
||||
}
|
||||
keycloak.init(loadData);
|
||||
|
||||
keycloak.init(loadData, loadFailure);
|
||||
|
||||
</script>
|
||||
|
||||
|
|
27
examples/test-cordova.json
Normal file
27
examples/test-cordova.json
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"id": "test",
|
||||
"realm": "test",
|
||||
"enabled": true,
|
||||
"sslNotRequired": 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" ],
|
||||
"users" : [
|
||||
{
|
||||
"username" : "test",
|
||||
"enabled": true,
|
||||
"email" : "test-user@localhost",
|
||||
"credentials" : [
|
||||
{ "type" : "password",
|
||||
"value" : "test" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"applications": [
|
||||
{
|
||||
"name": "test",
|
||||
"enabled": true,
|
||||
"secret": "password"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -33,22 +33,22 @@ public class AccountSocialBean {
|
|||
for (SocialProvider provider : SocialLoader.load()) {
|
||||
String socialProviderId = provider.getId();
|
||||
if (socialConfig.containsKey(socialProviderId + ".key")) {
|
||||
String socialUsername = getSocialUsername(userSocialLinks, socialProviderId);
|
||||
SocialLinkModel socialLink = getSocialLink(userSocialLinks, socialProviderId);
|
||||
|
||||
String action = socialUsername!=null ? "remove" : "add";
|
||||
String action = socialLink != null ? "remove" : "add";
|
||||
String actionUrl = UriBuilder.fromUri(accountSocialUpdateUri).queryParam("action", action).queryParam("provider_id", socialProviderId).build().toString();
|
||||
|
||||
SocialLinkEntry entry = new SocialLinkEntry(socialProviderId, provider.getName(), socialUsername, actionUrl);
|
||||
SocialLinkEntry entry = new SocialLinkEntry(socialLink, provider.getName(), actionUrl);
|
||||
this.socialLinks.add(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getSocialUsername(Set<SocialLinkModel> userSocialLinks, String socialProviderId) {
|
||||
private SocialLinkModel getSocialLink(Set<SocialLinkModel> userSocialLinks, String socialProviderId) {
|
||||
for (SocialLinkModel link : userSocialLinks) {
|
||||
if (socialProviderId.equals(link.getSocialProvider())) {
|
||||
return link.getSocialUsername();
|
||||
return link;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -60,32 +60,34 @@ public class AccountSocialBean {
|
|||
|
||||
public class SocialLinkEntry {
|
||||
|
||||
private final String providerId;
|
||||
private SocialLinkModel link;
|
||||
private final String providerName;
|
||||
private final String socialUsername;
|
||||
private final String actionUrl;
|
||||
|
||||
public SocialLinkEntry(String providerId, String providerName, String socialUsername, String actionUrl) {
|
||||
this.providerId = providerId;
|
||||
public SocialLinkEntry(SocialLinkModel link, String providerName, String actionUrl) {
|
||||
this.link = link;
|
||||
this.providerName = providerName;
|
||||
this.socialUsername = socialUsername!=null ? socialUsername : "";
|
||||
this.actionUrl = actionUrl;
|
||||
}
|
||||
|
||||
public String getProviderId() {
|
||||
return providerId;
|
||||
return link != null ? link.getSocialProvider() : null;
|
||||
}
|
||||
|
||||
public String getProviderName() {
|
||||
return providerName;
|
||||
}
|
||||
|
||||
public String getSocialUserId() {
|
||||
return link != null ? link.getSocialUserId() : null;
|
||||
}
|
||||
|
||||
public String getSocialUsername() {
|
||||
return socialUsername;
|
||||
return link != null ? link.getSocialUsername() : null;
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
return !socialUsername.isEmpty();
|
||||
return link != null;
|
||||
}
|
||||
|
||||
public String getActionUrl() {
|
||||
|
|
|
@ -11,16 +11,16 @@
|
|||
<#list social.links as socialLink>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-2 col-md-2">
|
||||
<label for="${socialLink.providerId}" class="control-label">${socialLink.providerName}</label>
|
||||
<label for="${socialLink.providerId!}" class="control-label">${socialLink.providerName!}</label>
|
||||
</div>
|
||||
<div class="col-sm-5 col-md-5">
|
||||
<input disabled="true" class="form-control" value="${socialLink.socialUsername}">
|
||||
<input disabled="true" class="form-control" value="${socialLink.socialUsername!}">
|
||||
</div>
|
||||
<div class="col-sm-5 col-md-5">
|
||||
<#if socialLink.connected>
|
||||
<a href="${socialLink.actionUrl}" type="submit" class="btn btn-primary btn-lg">Remove ${socialLink.providerName}</a>
|
||||
<a href="${socialLink.actionUrl}" type="submit" class="btn btn-primary btn-lg">Remove ${socialLink.providerName!}</a>
|
||||
<#else>
|
||||
<a href="${socialLink.actionUrl}" type="submit" class="btn btn-primary btn-lg">Add ${socialLink.providerName}</a>
|
||||
<a href="${socialLink.actionUrl}" type="submit" class="btn btn-primary btn-lg">Add ${socialLink.providerName!}</a>
|
||||
</#if>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -43,6 +43,8 @@ public interface LoginForms {
|
|||
|
||||
public LoginForms setClient(ClientModel client);
|
||||
|
||||
public LoginForms setQueryParams(MultivaluedMap<String, String> queryParams);
|
||||
|
||||
public LoginForms setFormData(MultivaluedMap<String, String> formData);
|
||||
|
||||
public LoginForms setStatus(Response.Status status);
|
||||
|
|
|
@ -51,6 +51,7 @@ public class FreeMarkerLoginForms implements LoginForms {
|
|||
private Response.Status status = Response.Status.OK;
|
||||
private List<RoleModel> realmRolesRequested;
|
||||
private MultivaluedMap<String, RoleModel> resourceRolesRequested;
|
||||
private MultivaluedMap<String, String> queryParams;
|
||||
|
||||
public static enum MessageType {SUCCESS, WARNING, ERROR}
|
||||
|
||||
|
@ -114,7 +115,7 @@ public class FreeMarkerLoginForms implements LoginForms {
|
|||
}
|
||||
|
||||
private Response createResponse(LoginFormsPages page) {
|
||||
MultivaluedMap<String, String> queryParameterMap = uriInfo.getQueryParameters();
|
||||
MultivaluedMap<String, String> queryParameterMap = queryParams != null ? queryParams : uriInfo.getQueryParameters();
|
||||
|
||||
String requestURI = uriInfo.getBaseUri().getPath();
|
||||
UriBuilder uriBuilder = UriBuilder.fromUri(requestURI);
|
||||
|
@ -276,4 +277,9 @@ public class FreeMarkerLoginForms implements LoginForms {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoginForms setQueryParams(MultivaluedMap<String, String> queryParams) {
|
||||
this.queryParams = queryParams;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -194,13 +194,22 @@ var Keycloak = function (options) {
|
|||
if (token) {
|
||||
window.oauth.token = token;
|
||||
kc.token = token;
|
||||
|
||||
kc.tokenParsed = JSON.parse(atob(token.split('.')[1]));
|
||||
kc.authenticated = true;
|
||||
kc.subject = kc.tokenParsed.sub;
|
||||
kc.realmAccess = kc.tokenParsed.realm_access;
|
||||
kc.resourceAccess = kc.tokenParsed.resource_access;
|
||||
|
||||
for (var i = 0; i < idTokenProperties.length; i++) {
|
||||
var n = idTokenProperties[i];
|
||||
if (kc.tokenParsed[n]) {
|
||||
if (!kc.idToken) {
|
||||
kc.idToken = {};
|
||||
}
|
||||
kc.idToken[n] = kc.tokenParsed[n];
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(function() {
|
||||
successCallback && successCallback({ authenticated: kc.authenticated, subject: kc.subject });
|
||||
}, 0);
|
||||
|
@ -260,6 +269,35 @@ var Keycloak = function (options) {
|
|||
var uuid = s.join('');
|
||||
return uuid;
|
||||
}
|
||||
|
||||
var idTokenProperties = [
|
||||
"name",
|
||||
"given_name",
|
||||
"family_name",
|
||||
"middle_name",
|
||||
"nickname",
|
||||
"preferred_username",
|
||||
"profile",
|
||||
"picture",
|
||||
"website",
|
||||
"email",
|
||||
"email_verified",
|
||||
"gender",
|
||||
"birthdate",
|
||||
"zoneinfo",
|
||||
"locale",
|
||||
"phone_number",
|
||||
"phone_number_verified",
|
||||
"address",
|
||||
"updated_at",
|
||||
"formatted",
|
||||
"street_address",
|
||||
"locality",
|
||||
"region",
|
||||
"postal_code",
|
||||
"country",
|
||||
"claims_locales"
|
||||
]
|
||||
}
|
||||
|
||||
window.oauth = (function () {
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<html>
|
||||
<head>
|
||||
<script src="http://192.168.0.16/js/keycloak.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<button onclick="keycloak.login()">Login</button>
|
||||
|
||||
<script>
|
||||
var keycloak = Keycloak({ realm: 'test', clientId: 'test', clientSecret: 'password' });
|
||||
|
||||
keycloak.init(function () {
|
||||
console.debug('Token: ' + keycloak.tokenParsed);
|
||||
console.debug('Realm access: ' + keycloak.realmAccess);
|
||||
console.debug('Resource access: ' + keycloak.resourceAccess);
|
||||
|
||||
keycloak.loadUserProfile(function (profile) {
|
||||
console.debug(profile);
|
||||
}, function (error) {
|
||||
console.debug(error);
|
||||
})
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
8
keycloak.json
Normal file
8
keycloak.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"realm" : "test",
|
||||
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDddHi8/MoYNtdafydQ+e4P0qrvClCW0o/x9fAbZ09dET/VBZCU28M54LmgJT7snXfreyYBpaQpHkW52/tyuEcJ5KO28LIcvObDQFDq3Z7esrovHl4NRETJBF9Xqwt+XLTZF6m37fYzaUK6MVJzUHP9qmu90LYyyvQ+hBJD0GSw1QIDAQAB",
|
||||
"auth-server-url" : "http://localhost:8081/auth",
|
||||
"ssl-not-required" : true,
|
||||
"resource" : "test",
|
||||
"public-client" : true
|
||||
}
|
|
@ -5,11 +5,29 @@ package org.keycloak.models;
|
|||
*/
|
||||
public class SocialLinkModel {
|
||||
|
||||
private String socialUsername;
|
||||
private String socialUserId;
|
||||
private String socialProvider;
|
||||
private String socialUsername;
|
||||
|
||||
public SocialLinkModel(String socialProvider, String socialUsername) {
|
||||
public SocialLinkModel(String socialProvider, String socialUserId, String socialUsername) {
|
||||
this.socialUserId = socialUserId;
|
||||
this.socialProvider = socialProvider;
|
||||
this.socialUsername = socialUsername;
|
||||
}
|
||||
|
||||
public String getSocialUserId() {
|
||||
return socialUserId;
|
||||
}
|
||||
|
||||
public void setSocialUserId(String socialUserId) {
|
||||
this.socialUserId = socialUserId;
|
||||
}
|
||||
|
||||
public String getSocialProvider() {
|
||||
return socialProvider;
|
||||
}
|
||||
|
||||
public void setSocialProvider(String socialProvider) {
|
||||
this.socialProvider = socialProvider;
|
||||
}
|
||||
|
||||
|
@ -20,12 +38,4 @@ public class SocialLinkModel {
|
|||
public void setSocialUsername(String socialUsername) {
|
||||
this.socialUsername = socialUsername;
|
||||
}
|
||||
|
||||
public String getSocialProvider() {
|
||||
return socialProvider;
|
||||
}
|
||||
|
||||
public void setSocialProvider(String socialProvider) {
|
||||
this.socialProvider = socialProvider;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -543,13 +543,13 @@ public class RealmAdapter implements RealmModel {
|
|||
TypedQuery<UserEntity> query = em.createNamedQuery("findUserByLinkAndRealm", UserEntity.class);
|
||||
query.setParameter("realm", realm);
|
||||
query.setParameter("socialProvider", socialLink.getSocialProvider());
|
||||
query.setParameter("socialUsername", socialLink.getSocialUsername());
|
||||
query.setParameter("socialUserId", socialLink.getSocialUserId());
|
||||
List<UserEntity> results = query.getResultList();
|
||||
if (results.isEmpty()) {
|
||||
return null;
|
||||
} else if (results.size() > 1) {
|
||||
throw new IllegalStateException("More results found for socialProvider=" + socialLink.getSocialProvider() +
|
||||
", socialUsername=" + socialLink.getSocialUsername() + ", results=" + results);
|
||||
", socialUserId=" + socialLink.getSocialUserId() + ", results=" + results);
|
||||
} else {
|
||||
UserEntity user = results.get(0);
|
||||
return new UserAdapter(user);
|
||||
|
@ -563,7 +563,7 @@ public class RealmAdapter implements RealmModel {
|
|||
List<SocialLinkEntity> results = query.getResultList();
|
||||
Set<SocialLinkModel> set = new HashSet<SocialLinkModel>();
|
||||
for (SocialLinkEntity entity : results) {
|
||||
set.add(new SocialLinkModel(entity.getSocialProvider(), entity.getSocialUsername()));
|
||||
set.add(new SocialLinkModel(entity.getSocialProvider(), entity.getSocialUserId(), entity.getSocialUsername()));
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
@ -571,7 +571,7 @@ public class RealmAdapter implements RealmModel {
|
|||
@Override
|
||||
public SocialLinkModel getSocialLink(UserModel user, String socialProvider) {
|
||||
SocialLinkEntity entity = findSocialLink(user, socialProvider);
|
||||
return (entity != null) ? new SocialLinkModel(entity.getSocialProvider(), entity.getSocialUsername()) : null;
|
||||
return (entity != null) ? new SocialLinkModel(entity.getSocialProvider(), entity.getSocialUserId(), entity.getSocialUsername()) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -579,6 +579,7 @@ public class RealmAdapter implements RealmModel {
|
|||
SocialLinkEntity entity = new SocialLinkEntity();
|
||||
entity.setRealm(realm);
|
||||
entity.setSocialProvider(socialLink.getSocialProvider());
|
||||
entity.setSocialUserId(socialLink.getSocialUserId());
|
||||
entity.setSocialUsername(socialLink.getSocialUsername());
|
||||
entity.setUser(((UserAdapter) user).getUser());
|
||||
em.persist(entity);
|
||||
|
|
|
@ -16,7 +16,7 @@ import org.hibernate.annotations.GenericGenerator;
|
|||
@NamedQueries({
|
||||
@NamedQuery(name="findSocialLinkByUser", query="select link from SocialLinkEntity link where link.user = :user"),
|
||||
@NamedQuery(name="findSocialLinkByUserAndProvider", query="select link from SocialLinkEntity link where link.user = :user and link.socialProvider = :socialProvider"),
|
||||
@NamedQuery(name="findUserByLinkAndRealm", query="select link.user from SocialLinkEntity link where link.realm = :realm and link.socialProvider = :socialProvider and link.socialUsername = :socialUsername")
|
||||
@NamedQuery(name="findUserByLinkAndRealm", query="select link.user from SocialLinkEntity link where link.realm = :realm and link.socialProvider = :socialProvider and link.socialUserId = :socialUserId")
|
||||
})
|
||||
@Entity
|
||||
public class SocialLinkEntity {
|
||||
|
@ -32,6 +32,7 @@ public class SocialLinkEntity {
|
|||
protected RealmEntity realm;
|
||||
|
||||
protected String socialProvider;
|
||||
protected String socialUserId;
|
||||
protected String socialUsername;
|
||||
|
||||
public String getId() {
|
||||
|
@ -58,6 +59,14 @@ public class SocialLinkEntity {
|
|||
this.socialProvider = socialProvider;
|
||||
}
|
||||
|
||||
public String getSocialUserId() {
|
||||
return socialUserId;
|
||||
}
|
||||
|
||||
public void setSocialUserId(String socialUserId) {
|
||||
this.socialUserId = socialUserId;
|
||||
}
|
||||
|
||||
public String getSocialUsername() {
|
||||
return socialUsername;
|
||||
}
|
||||
|
|
|
@ -853,7 +853,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
|
|||
public UserModel getUserBySocialLink(SocialLinkModel socialLink) {
|
||||
DBObject query = new QueryBuilder()
|
||||
.and("socialLinks.socialProvider").is(socialLink.getSocialProvider())
|
||||
.and("socialLinks.socialUsername").is(socialLink.getSocialUsername())
|
||||
.and("socialLinks.socialUserId").is(socialLink.getSocialUserId())
|
||||
.and("realmId").is(getId())
|
||||
.get();
|
||||
UserEntity userEntity = getMongoStore().loadSingleEntity(UserEntity.class, query, invocationContext);
|
||||
|
@ -871,7 +871,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
|
|||
|
||||
Set<SocialLinkModel> result = new HashSet<SocialLinkModel>();
|
||||
for (SocialLinkEntity socialLinkEntity : linkEntities) {
|
||||
SocialLinkModel model = new SocialLinkModel(socialLinkEntity.getSocialProvider(), socialLinkEntity.getSocialUsername());
|
||||
SocialLinkModel model = new SocialLinkModel(socialLinkEntity.getSocialProvider(), socialLinkEntity.getSocialUserId(), socialLinkEntity.getSocialUsername());
|
||||
result.add(model);
|
||||
}
|
||||
return result;
|
||||
|
@ -880,7 +880,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
|
|||
@Override
|
||||
public SocialLinkModel getSocialLink(UserModel user, String socialProvider) {
|
||||
SocialLinkEntity socialLinkEntity = findSocialLink(user, socialProvider);
|
||||
return socialLinkEntity!=null ? new SocialLinkModel(socialLinkEntity.getSocialProvider(), socialLinkEntity.getSocialUsername()) : null;
|
||||
return socialLinkEntity!=null ? new SocialLinkModel(socialLinkEntity.getSocialProvider(), socialLinkEntity.getSocialUserId(), socialLinkEntity.getSocialUsername()) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -888,6 +888,7 @@ public class RealmAdapter extends AbstractMongoAdapter<RealmEntity> implements R
|
|||
UserEntity userEntity = ((UserAdapter)user).getUser();
|
||||
SocialLinkEntity socialLinkEntity = new SocialLinkEntity();
|
||||
socialLinkEntity.setSocialProvider(socialLink.getSocialProvider());
|
||||
socialLinkEntity.setSocialUserId(socialLink.getSocialUserId());
|
||||
socialLinkEntity.setSocialUsername(socialLink.getSocialUsername());
|
||||
|
||||
getMongoStore().pushItemToList(userEntity, "socialLinks", socialLinkEntity, true, invocationContext);
|
||||
|
|
|
@ -8,9 +8,19 @@ import org.keycloak.models.mongo.api.MongoField;
|
|||
*/
|
||||
public class SocialLinkEntity implements MongoEntity {
|
||||
|
||||
private String socialUserId;
|
||||
private String socialUsername;
|
||||
private String socialProvider;
|
||||
|
||||
@MongoField
|
||||
public String getSocialUserId() {
|
||||
return socialUserId;
|
||||
}
|
||||
|
||||
public void setSocialUserId(String socialUserId) {
|
||||
this.socialUserId = socialUserId;
|
||||
}
|
||||
|
||||
@MongoField
|
||||
public String getSocialUsername() {
|
||||
return socialUsername;
|
||||
|
@ -37,9 +47,9 @@ public class SocialLinkEntity implements MongoEntity {
|
|||
SocialLinkEntity that = (SocialLinkEntity) o;
|
||||
|
||||
if (socialProvider != null && (that.socialProvider == null || !socialProvider.equals(that.socialProvider))) return false;
|
||||
if (socialUsername != null && (that.socialUsername == null || !socialUsername.equals(that.socialUsername))) return false;
|
||||
if (socialUserId != null && (that.socialUserId == null || !socialUserId.equals(that.socialUserId))) return false;
|
||||
if (socialProvider == null && that.socialProvider != null)return false;
|
||||
if (socialUsername == null && that.socialUsername != null) return false;
|
||||
if (socialUserId == null && that.socialUserId != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -47,7 +57,7 @@ public class SocialLinkEntity implements MongoEntity {
|
|||
@Override
|
||||
public int hashCode() {
|
||||
int code = 1;
|
||||
if (socialUsername != null) {
|
||||
if (socialUserId != null) {
|
||||
code = code * 13;
|
||||
}
|
||||
if (socialProvider != null) {
|
||||
|
|
|
@ -880,14 +880,14 @@ public class RealmAdapter implements RealmModel {
|
|||
public UserModel getUserBySocialLink(SocialLinkModel socialLink) {
|
||||
RelationshipQuery<SocialLinkRelationship> query = getRelationshipManager().createRelationshipQuery(SocialLinkRelationship.class);
|
||||
query.setParameter(SocialLinkRelationship.SOCIAL_PROVIDER, socialLink.getSocialProvider());
|
||||
query.setParameter(SocialLinkRelationship.SOCIAL_USERNAME, socialLink.getSocialUsername());
|
||||
query.setParameter(SocialLinkRelationship.SOCIAL_USERNAME, socialLink.getSocialUserId());
|
||||
query.setParameter(SocialLinkRelationship.REALM, realm.getName());
|
||||
List<SocialLinkRelationship> results = query.getResultList();
|
||||
if (results.isEmpty()) {
|
||||
return null;
|
||||
} else if (results.size() > 1) {
|
||||
throw new IllegalStateException("More results found for socialProvider=" + socialLink.getSocialProvider() +
|
||||
", socialUsername=" + socialLink.getSocialUsername() + ", results=" + results);
|
||||
", socialUserId=" + socialLink.getSocialUserId() + ", results=" + results);
|
||||
} else {
|
||||
User user = results.get(0).getUser();
|
||||
return new UserAdapter(user, getIdm());
|
||||
|
@ -902,7 +902,7 @@ public class RealmAdapter implements RealmModel {
|
|||
|
||||
Set<SocialLinkModel> results = new HashSet<SocialLinkModel>();
|
||||
for (SocialLinkRelationship relationship : plSocialLinks) {
|
||||
results.add(new SocialLinkModel(relationship.getSocialProvider(), relationship.getSocialUsername()));
|
||||
results.add(new SocialLinkModel(relationship.getSocialProvider(), relationship.getSocialUserId()));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
@ -912,7 +912,7 @@ public class RealmAdapter implements RealmModel {
|
|||
SocialLinkRelationship relationship = new SocialLinkRelationship();
|
||||
relationship.setUser(((UserAdapter)user).getUser());
|
||||
relationship.setSocialProvider(socialLink.getSocialProvider());
|
||||
relationship.setSocialUsername(socialLink.getSocialUsername());
|
||||
relationship.setSocialUserId(socialLink.getSocialUserId());
|
||||
relationship.setRealm(realm.getName());
|
||||
|
||||
getRelationshipManager().add(relationship);
|
||||
|
@ -923,7 +923,7 @@ public class RealmAdapter implements RealmModel {
|
|||
SocialLinkRelationship relationship = new SocialLinkRelationship();
|
||||
relationship.setUser(((UserAdapter)user).getUser());
|
||||
relationship.setSocialProvider(socialLink.getSocialProvider());
|
||||
relationship.setSocialUsername(socialLink.getSocialUsername());
|
||||
relationship.setSocialUserId(socialLink.getSocialUserId());
|
||||
relationship.setRealm(realm.getName());
|
||||
|
||||
getRelationshipManager().remove(relationship);
|
||||
|
|
|
@ -20,9 +20,9 @@ public class SocialLinkRelationship extends AbstractAttributedType implements Re
|
|||
private static final long serialVersionUID = 154879L;
|
||||
|
||||
public static final AttributeParameter SOCIAL_PROVIDER = new AttributeParameter("socialProvider");
|
||||
public static final AttributeParameter SOCIAL_USERNAME = new AttributeParameter("socialUsername");
|
||||
public static final AttributeParameter SOCIAL_USERID = new AttributeParameter("socialUserId");
|
||||
|
||||
// realm is needed to allow searching as combination socialUsername+socialProvider may not be unique
|
||||
// realm is needed to allow searching as combination socialUserId+socialProvider may not be unique
|
||||
// (Same user could have mapped same facebook account to username "foo" in "realm1" and to username "bar" in "realm2")
|
||||
public static final AttributeParameter REALM = new AttributeParameter("realm");
|
||||
|
||||
|
@ -54,12 +54,12 @@ public class SocialLinkRelationship extends AbstractAttributedType implements Re
|
|||
}
|
||||
|
||||
@AttributeProperty
|
||||
public String getSocialUsername() {
|
||||
return (String)getAttribute("socialUsername").getValue();
|
||||
public String getSocialUserId() {
|
||||
return (String)getAttribute("socialUserId").getValue();
|
||||
}
|
||||
|
||||
public void setSocialUsername(String socialProviderUserId) {
|
||||
setAttribute(new Attribute<String>("socialUsername", socialProviderUserId));
|
||||
public void setSocialUserId(String socialUserId) {
|
||||
setAttribute(new Attribute<String>("socialUserId", socialUserId));
|
||||
}
|
||||
|
||||
@AttributeProperty
|
||||
|
|
|
@ -156,7 +156,7 @@ public class AdapterTest extends AbstractModelTest {
|
|||
RoleModel appRole = app.addRole("test");
|
||||
realmModel.grantRole(user, appRole);
|
||||
|
||||
SocialLinkModel socialLink = new SocialLinkModel("google", user.getLoginName());
|
||||
SocialLinkModel socialLink = new SocialLinkModel("google", "google1", user.getLoginName());
|
||||
realmModel.addSocialLink(user, socialLink);
|
||||
|
||||
UserCredentialModel cred = new UserCredentialModel();
|
||||
|
|
|
@ -133,22 +133,26 @@ public class ImportTest extends AbstractModelTest {
|
|||
for (SocialLinkModel socialLinkModel : socialLinks) {
|
||||
if ("facebook".equals(socialLinkModel.getSocialProvider())) {
|
||||
facebookFound = true;
|
||||
Assert.assertEquals(socialLinkModel.getSocialUserId(), "facebook1");
|
||||
Assert.assertEquals(socialLinkModel.getSocialUsername(), "fbuser1");
|
||||
} else if ("google".equals(socialLinkModel.getSocialProvider())) {
|
||||
googleFound = true;
|
||||
Assert.assertEquals(socialLinkModel.getSocialUserId(), "google1");
|
||||
Assert.assertEquals(socialLinkModel.getSocialUsername(), "mySocialUser@gmail.com");
|
||||
} else if ("twitter".equals(socialLinkModel.getSocialProvider())) {
|
||||
twitterFound = true;
|
||||
Assert.assertEquals(socialLinkModel.getSocialUserId(), "twitter1");
|
||||
Assert.assertEquals(socialLinkModel.getSocialUsername(), "twuser1");
|
||||
}
|
||||
}
|
||||
Assert.assertTrue(facebookFound && twitterFound && googleFound);
|
||||
|
||||
UserModel foundSocialUser = realm.getUserBySocialLink(new SocialLinkModel("facebook", "fbuser1"));
|
||||
UserModel foundSocialUser = realm.getUserBySocialLink(new SocialLinkModel("facebook", "facebook1", "fbuser1"));
|
||||
Assert.assertEquals(foundSocialUser.getLoginName(), socialUser.getLoginName());
|
||||
Assert.assertNull(realm.getUserBySocialLink(new SocialLinkModel("facebook", "not-existing")));
|
||||
Assert.assertNull(realm.getUserBySocialLink(new SocialLinkModel("facebook", "not-existing", "not-existing")));
|
||||
|
||||
SocialLinkModel foundSocialLink = realm.getSocialLink(socialUser, "facebook");
|
||||
Assert.assertEquals("facebook1", foundSocialLink.getSocialUserId());
|
||||
Assert.assertEquals("fbuser1", foundSocialLink.getSocialUsername());
|
||||
Assert.assertEquals("facebook", foundSocialLink.getSocialProvider());
|
||||
|
||||
|
|
|
@ -52,14 +52,17 @@
|
|||
"socialLinks": [
|
||||
{
|
||||
"socialProvider": "facebook",
|
||||
"socialUserId": "facebook1",
|
||||
"socialUsername": "fbuser1"
|
||||
},
|
||||
{
|
||||
"socialProvider": "twitter",
|
||||
"socialUserId": "twitter1",
|
||||
"socialUsername": "twuser1"
|
||||
},
|
||||
{
|
||||
"socialProvider": "google",
|
||||
"socialUserId": "google1",
|
||||
"socialUsername": "mySocialUser@gmail.com"
|
||||
}
|
||||
]
|
||||
|
|
|
@ -366,7 +366,7 @@ public class RealmManager {
|
|||
for (SocialMappingRepresentation socialMapping : rep.getSocialMappings()) {
|
||||
UserModel user = userMap.get(socialMapping.getUsername());
|
||||
for (SocialLinkRepresentation link : socialMapping.getSocialLinks()) {
|
||||
SocialLinkModel mappingModel = new SocialLinkModel(link.getSocialProvider(), link.getSocialUsername());
|
||||
SocialLinkModel mappingModel = new SocialLinkModel(link.getSocialProvider(), link.getSocialUserId(), link.getSocialUsername());
|
||||
newRealm.addSocialLink(user, mappingModel);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ package org.keycloak.services.resources;
|
|||
|
||||
import org.jboss.resteasy.logging.Logger;
|
||||
import org.jboss.resteasy.spi.HttpRequest;
|
||||
import org.jboss.resteasy.spi.HttpResponse;
|
||||
import org.keycloak.models.AccountRoles;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.Constants;
|
||||
|
@ -32,22 +31,20 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.SocialLinkModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.services.managers.AppAuthManager;
|
||||
import org.keycloak.services.managers.Auth;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.managers.SocialRequestManager;
|
||||
import org.keycloak.services.managers.TokenManager;
|
||||
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;
|
||||
import org.keycloak.social.SocialAccessDeniedException;
|
||||
import org.keycloak.social.SocialLoader;
|
||||
import org.keycloak.social.SocialProvider;
|
||||
import org.keycloak.social.SocialProviderConfig;
|
||||
import org.keycloak.social.SocialProviderException;
|
||||
import org.keycloak.services.managers.SocialRequestManager;
|
||||
import org.keycloak.social.SocialUser;
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
|
@ -57,6 +54,7 @@ import javax.ws.rs.QueryParam;
|
|||
import javax.ws.rs.container.ResourceContext;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MultivaluedHashMap;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
|
@ -141,12 +139,20 @@ public class SocialResource {
|
|||
SocialUser socialUser;
|
||||
try {
|
||||
socialUser = provider.processCallback(config, callback);
|
||||
} catch (SocialAccessDeniedException e) {
|
||||
MultivaluedHashMap<String, String> queryParms = new MultivaluedHashMap<String, String>();
|
||||
queryParms.putSingle("client_id", requestData.getClientAttribute("clientId"));
|
||||
queryParms.putSingle("state", requestData.getClientAttribute("state"));
|
||||
queryParms.putSingle("scope", requestData.getClientAttribute("scope"));
|
||||
queryParms.putSingle("redirect_uri", requestData.getClientAttribute("redirectUri"));
|
||||
queryParms.putSingle("response_type", requestData.getClientAttribute("responseType"));
|
||||
return Flows.forms(realm, request, uriInfo).setQueryParams(queryParms).setWarning("Access denied").createLogin();
|
||||
} catch (SocialProviderException e) {
|
||||
logger.warn("Failed to process social callback", e);
|
||||
return oauth.forwardToSecurityFailure("Failed to process social callback");
|
||||
}
|
||||
|
||||
SocialLinkModel socialLink = new SocialLinkModel(provider.getId(), socialUser.getId());
|
||||
SocialLinkModel socialLink = new SocialLinkModel(provider.getId(), socialUser.getId(), socialUser.getUsername());
|
||||
UserModel user = realm.getUserBySocialLink(socialLink);
|
||||
|
||||
// Check if user is already authenticated (this means linking social into existing user account)
|
||||
|
@ -210,7 +216,7 @@ public class SocialResource {
|
|||
public Response redirectToProviderAuth(@PathParam("realm") final String realmName,
|
||||
@QueryParam("provider_id") final String providerId, @QueryParam("client_id") final String clientId,
|
||||
@QueryParam("scope") final String scope, @QueryParam("state") final String state,
|
||||
@QueryParam("redirect_uri") String redirectUri) {
|
||||
@QueryParam("redirect_uri") String redirectUri, @QueryParam("response_type") String responseType) {
|
||||
RealmManager realmManager = new RealmManager(session);
|
||||
RealmModel realm = realmManager.getRealmByName(realmName);
|
||||
|
||||
|
@ -239,20 +245,24 @@ public class SocialResource {
|
|||
.putClientAttribute("realm", realmName)
|
||||
.putClientAttribute("clientId", clientId).putClientAttribute("scope", scope)
|
||||
.putClientAttribute("state", state).putClientAttribute("redirectUri", redirectUri)
|
||||
.redirectToSocialProvider();
|
||||
.putClientAttribute("responseType", responseType).redirectToSocialProvider();
|
||||
} catch (Throwable t) {
|
||||
return Flows.forms(realm, request, uriInfo).setError("Failed to redirect to social auth").createErrorPage();
|
||||
}
|
||||
}
|
||||
|
||||
private RequestDetails getRequestDetails(Map<String, String[]> queryParams) {
|
||||
for (SocialProvider provider : SocialLoader.load()) {
|
||||
if (queryParams.containsKey(provider.getRequestIdParamName())) {
|
||||
String requestId = queryParams.get(provider.getRequestIdParamName())[0];
|
||||
if (socialRequestManager.isRequestId(requestId)) {
|
||||
return socialRequestManager.retrieveData(requestId);
|
||||
}
|
||||
}
|
||||
String requestId = null;
|
||||
if (queryParams.containsKey("state")) {
|
||||
requestId = queryParams.get("state")[0];
|
||||
} else if (queryParams.containsKey("oauth_token")) {
|
||||
requestId = queryParams.get("oauth_token")[0];
|
||||
} else if (queryParams.containsKey("denied")) {
|
||||
requestId = queryParams.get("denied")[0];
|
||||
}
|
||||
|
||||
if (requestId != null && socialRequestManager.isRequestId(requestId)) {
|
||||
return socialRequestManager.retrieveData(requestId);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -51,6 +51,15 @@ public abstract class AbstractOAuth2Provider implements SocialProvider {
|
|||
|
||||
@Override
|
||||
public SocialUser processCallback(SocialProviderConfig config, AuthCallback callback) throws SocialProviderException {
|
||||
String error = callback.getQueryParam("error");
|
||||
if (error != null) {
|
||||
if (error.equals("access_denied")) {
|
||||
throw new SocialAccessDeniedException();
|
||||
} else {
|
||||
throw new SocialProviderException(error);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
String code = callback.getQueryParam(CODE);
|
||||
|
||||
|
@ -82,9 +91,4 @@ public abstract class AbstractOAuth2Provider implements SocialProvider {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestIdParamName() {
|
||||
return STATE;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ public class AuthCallback {
|
|||
|
||||
public String getQueryParam(String name) {
|
||||
String[] value = queryParams.get(name);
|
||||
if (value.length > 0) {
|
||||
if (value != null && value.length > 0) {
|
||||
return value[0];
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package org.keycloak.social;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class SocialAccessDeniedException extends SocialProviderException {
|
||||
}
|
|
@ -31,8 +31,6 @@ public interface SocialProvider {
|
|||
|
||||
AuthRequest getAuthUrl(SocialProviderConfig config) throws SocialProviderException;
|
||||
|
||||
String getRequestIdParamName();
|
||||
|
||||
String getName();
|
||||
|
||||
SocialUser processCallback(SocialProviderConfig config, AuthCallback callback) throws SocialProviderException;
|
||||
|
|
|
@ -28,6 +28,9 @@ public class SocialProviderException extends Exception {
|
|||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected SocialProviderException() {
|
||||
}
|
||||
|
||||
public SocialProviderException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
|
|
@ -3,12 +3,14 @@ package org.keycloak.social;
|
|||
public class SocialUser {
|
||||
|
||||
private String id;
|
||||
private String username;
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
private String email;
|
||||
|
||||
public SocialUser(String id) {
|
||||
public SocialUser(String id, String username) {
|
||||
this.id = id;
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
|
@ -19,6 +21,14 @@ public class SocialUser {
|
|||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ public class FacebookProvider extends AbstractOAuth2Provider {
|
|||
try {
|
||||
JSONObject profile = SimpleHttp.doGet(PROFILE_URL).header("Authorization", "Bearer " + accessToken).asJson();
|
||||
|
||||
SocialUser user = new SocialUser(profile.getString("id"));
|
||||
SocialUser user = new SocialUser(profile.getString("id"), profile.getString("username"));
|
||||
user.setName(profile.optString("first_name"), profile.optString("last_name"));
|
||||
user.setEmail(profile.optString("email"));
|
||||
|
||||
|
@ -64,10 +64,6 @@ public class FacebookProvider extends AbstractOAuth2Provider {
|
|||
|
||||
@Override
|
||||
public AuthRequest getAuthUrl(SocialProviderConfig config) throws SocialProviderException {
|
||||
if (config.getCallbackUrl().contains("//localhost")) {
|
||||
String callbackUrl = config.getCallbackUrl().replace("//localhost", "//127.0.0.1");
|
||||
config = new SocialProviderConfig(config.getKey(), config.getSecret(), callbackUrl);
|
||||
}
|
||||
return super.getAuthUrl(config);
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ public class GitHubProvider extends AbstractOAuth2Provider {
|
|||
try {
|
||||
JSONObject profile = SimpleHttp.doGet(PROFILE_URL).header("Authorization", "Bearer " + accessToken).asJson();
|
||||
|
||||
SocialUser user = new SocialUser(profile.get("id").toString());
|
||||
SocialUser user = new SocialUser(profile.get("id").toString(), profile.getString("login"));
|
||||
user.setName(profile.optString("name"));
|
||||
user.setEmail(profile.optString("email"));
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ public class GoogleProvider extends AbstractOAuth2Provider {
|
|||
try {
|
||||
JSONObject profile = SimpleHttp.doGet(PROFILE_URL).header("Authorization", "Bearer " + accessToken).asJson();
|
||||
|
||||
SocialUser user = new SocialUser(profile.getString("sub"));
|
||||
SocialUser user = new SocialUser(profile.getString("sub"), profile.getString("email"));
|
||||
user.setName(profile.optString("given_name"), profile.optString("family_name"));
|
||||
user.setEmail(profile.optString("email"));
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ package org.keycloak.social.twitter;
|
|||
|
||||
import org.keycloak.social.AuthCallback;
|
||||
import org.keycloak.social.AuthRequest;
|
||||
import org.keycloak.social.SocialAccessDeniedException;
|
||||
import org.keycloak.social.SocialProvider;
|
||||
import org.keycloak.social.SocialProviderConfig;
|
||||
import org.keycloak.social.SocialProviderException;
|
||||
|
@ -67,6 +68,10 @@ public class TwitterProvider implements SocialProvider {
|
|||
|
||||
@Override
|
||||
public SocialUser processCallback(SocialProviderConfig config, AuthCallback callback) throws SocialProviderException {
|
||||
if (callback.getQueryParam("denied") != null) {
|
||||
throw new SocialAccessDeniedException();
|
||||
}
|
||||
|
||||
try {
|
||||
Twitter twitter = new TwitterFactory().getInstance();
|
||||
twitter.setOAuthConsumer(config.getKey(), config.getSecret());
|
||||
|
@ -77,7 +82,7 @@ public class TwitterProvider implements SocialProvider {
|
|||
twitter.getOAuthAccessToken(requestToken, verifier);
|
||||
twitter4j.User twitterUser = twitter.verifyCredentials();
|
||||
|
||||
SocialUser user = new SocialUser(Long.toString(twitterUser.getId()));
|
||||
SocialUser user = new SocialUser(Long.toString(twitterUser.getId()), twitterUser.getScreenName());
|
||||
user.setName(twitterUser.getName());
|
||||
|
||||
return user;
|
||||
|
@ -86,9 +91,4 @@ public class TwitterProvider implements SocialProvider {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestIdParamName() {
|
||||
return "oauth_token";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -202,11 +202,12 @@ public class KeycloakServer {
|
|||
try {
|
||||
RealmManager manager = new RealmManager(session);
|
||||
|
||||
if (rep.getId() == null) {
|
||||
throw new RuntimeException("Realm id not specified");
|
||||
if (rep.getId() != null && manager.getRealm(rep.getId()) != null) {
|
||||
info("Not importing realm " + rep.getRealm() + " realm already exists");
|
||||
return;
|
||||
}
|
||||
|
||||
if (manager.getRealm(rep.getId()) != null) {
|
||||
if (manager.getRealmByName(rep.getRealm()) != null) {
|
||||
info("Not importing realm " + rep.getRealm() + " realm already exists");
|
||||
return;
|
||||
}
|
||||
|
@ -268,7 +269,7 @@ public class KeycloakServer {
|
|||
|
||||
server.deploy(di);
|
||||
|
||||
factory = ((KeycloakApplication)deployment.getApplication()).getFactory();
|
||||
factory = ((KeycloakApplication) deployment.getApplication()).getFactory();
|
||||
|
||||
setupDevConfig();
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.keycloak.testsuite;
|
|||
|
||||
import org.keycloak.social.AuthCallback;
|
||||
import org.keycloak.social.AuthRequest;
|
||||
import org.keycloak.social.SocialAccessDeniedException;
|
||||
import org.keycloak.social.SocialProvider;
|
||||
import org.keycloak.social.SocialProviderConfig;
|
||||
import org.keycloak.social.SocialProviderException;
|
||||
|
@ -26,11 +27,6 @@ public class DummySocial implements SocialProvider {
|
|||
.setQueryParam("redirect_uri", config.getCallbackUrl()).setQueryParam("state", state).setAttribute("state", state).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestIdParamName() {
|
||||
return "state";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Dummy Provider";
|
||||
|
@ -38,12 +34,18 @@ public class DummySocial implements SocialProvider {
|
|||
|
||||
@Override
|
||||
public SocialUser processCallback(SocialProviderConfig config, AuthCallback callback) throws SocialProviderException {
|
||||
String error = callback.getQueryParam("error");
|
||||
if (error != null) {
|
||||
throw new SocialAccessDeniedException();
|
||||
}
|
||||
|
||||
if (!callback.getQueryParam("state").equals(callback.getAttribute("state"))) {
|
||||
throw new SocialProviderException("Invalid state");
|
||||
}
|
||||
|
||||
String id = callback.getQueryParam("id");
|
||||
String username = callback.getQueryParam("username");
|
||||
SocialUser user = new SocialUser(username);
|
||||
SocialUser user = new SocialUser(id, username);
|
||||
user.setName(callback.getQueryParam("firstname"), callback.getQueryParam("lastname"));
|
||||
user.setEmail(callback.getQueryParam("email"));
|
||||
return user;
|
||||
|
|
|
@ -22,11 +22,13 @@ public class DummySocialServlet extends HttpServlet {
|
|||
pw.print("<html>");
|
||||
pw.print("<body>");
|
||||
pw.print("<form method=\"post\">");
|
||||
pw.print("<label for=\"id\">ID</label><input type=\"text\" id=\"id\" name=\"id\" />");
|
||||
pw.print("<label for=\"username\">Username</label><input type=\"text\" id=\"username\" name=\"username\" />");
|
||||
pw.print("<label for=\"firstname\">First Name</label><input type=\"text\" id=\"firstname\" name=\"firstname\" />");
|
||||
pw.print("<label for=\"lastname\">Last Name</label><input type=\"text\" id=\"lastname\" name=\"lastname\" />");
|
||||
pw.print("<label for=\"email\">Email</label><input type=\"text\" id=\"email\" name=\"email\" />");
|
||||
pw.print("<input type=\"submit\" id=\"submit\" value=\"login\" />");
|
||||
pw.print("<input type=\"submit\" id=\"login\" name=\"login\" value=\"login\" />");
|
||||
pw.print("<input type=\"submit\" id=\"cancel\" name=\"cancel\" value=\"cancel\" />");
|
||||
pw.print("</form>");
|
||||
pw.print("</body>");
|
||||
pw.print("</html>");
|
||||
|
@ -53,15 +55,20 @@ public class DummySocialServlet extends HttpServlet {
|
|||
}
|
||||
}
|
||||
|
||||
String redirect = redirectUri + "?username=" + req.getParameter("username") + "&state=" + state + "&code=" + UUID.randomUUID().toString();
|
||||
if (req.getParameter("firstname") != null) {
|
||||
redirect += "&firstname=" + req.getParameter("firstname");
|
||||
}
|
||||
if (req.getParameter("lastname") != null) {
|
||||
redirect += "&lastname=" + req.getParameter("lastname");
|
||||
}
|
||||
if (req.getParameter("email") != null) {
|
||||
redirect += "&email=" + req.getParameter("email");
|
||||
String redirect;
|
||||
if (req.getParameter("login") != null) {
|
||||
redirect = redirectUri + "?id=" + req.getParameter("id") + "&username=" + req.getParameter("username") + "&state=" + state + "&code=" + UUID.randomUUID().toString();
|
||||
if (req.getParameter("firstname") != null) {
|
||||
redirect += "&firstname=" + req.getParameter("firstname");
|
||||
}
|
||||
if (req.getParameter("lastname") != null) {
|
||||
redirect += "&lastname=" + req.getParameter("lastname");
|
||||
}
|
||||
if (req.getParameter("email") != null) {
|
||||
redirect += "&email=" + req.getParameter("email");
|
||||
}
|
||||
} else {
|
||||
redirect = redirectUri + "?error=access_denied&state=" + state;
|
||||
}
|
||||
|
||||
resp.sendRedirect(redirect);
|
||||
|
|
|
@ -62,6 +62,9 @@ public class LoginPage extends AbstractPage {
|
|||
@FindBy(className = "feedback-error")
|
||||
private WebElement loginErrorMessage;
|
||||
|
||||
@FindBy(className = "feedback-warning")
|
||||
private WebElement loginWarningMessage;
|
||||
|
||||
public void login(String username, String password) {
|
||||
usernameInput.clear();
|
||||
usernameInput.sendKeys(username);
|
||||
|
@ -80,6 +83,11 @@ public class LoginPage extends AbstractPage {
|
|||
return loginErrorMessage != null ? loginErrorMessage.getText() : null;
|
||||
}
|
||||
|
||||
public String getWarning() {
|
||||
return loginWarningMessage != null ? loginWarningMessage.getText() : null;
|
||||
}
|
||||
|
||||
|
||||
public boolean isCurrent() {
|
||||
return driver.getTitle().equals("Log in to test");
|
||||
}
|
||||
|
|
|
@ -97,11 +97,12 @@ public class SocialLoginTest {
|
|||
|
||||
loginPage.clickSocial("dummy");
|
||||
|
||||
driver.findElement(By.id("id")).sendKeys("1");
|
||||
driver.findElement(By.id("username")).sendKeys("dummy-user1");
|
||||
driver.findElement(By.id("firstname")).sendKeys("Bob");
|
||||
driver.findElement(By.id("lastname")).sendKeys("Builder");
|
||||
driver.findElement(By.id("email")).sendKeys("bob@builder.com");
|
||||
driver.findElement(By.id("submit")).click();
|
||||
driver.findElement(By.id("login")).click();
|
||||
|
||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
|
||||
|
@ -118,6 +119,23 @@ public class SocialLoginTest {
|
|||
Assert.assertEquals("bob@builder.com", profile.getEmail());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void loginCancelled() throws Exception {
|
||||
loginPage.open();
|
||||
|
||||
loginPage.clickSocial("dummy");
|
||||
|
||||
driver.findElement(By.id("cancel")).click();
|
||||
|
||||
Assert.assertTrue(loginPage.isCurrent());
|
||||
Assert.assertEquals("Access denied", loginPage.getWarning());
|
||||
|
||||
loginPage.login("test-user@localhost", "password");
|
||||
|
||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void profileUpdateRequired() {
|
||||
keycloakRule.configure(new KeycloakSetup() {
|
||||
|
@ -132,11 +150,12 @@ public class SocialLoginTest {
|
|||
|
||||
loginPage.clickSocial("dummy");
|
||||
|
||||
driver.findElement(By.id("id")).sendKeys("2");
|
||||
driver.findElement(By.id("username")).sendKeys("dummy-user2");
|
||||
driver.findElement(By.id("firstname")).sendKeys("Bob");
|
||||
driver.findElement(By.id("lastname")).sendKeys("Builder");
|
||||
driver.findElement(By.id("email")).sendKeys("bob@builder.com");
|
||||
driver.findElement(By.id("submit")).click();
|
||||
driver.findElement(By.id("login")).click();
|
||||
|
||||
profilePage.isCurrent();
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ public class CreateUsersWorker implements Worker {
|
|||
+ " which is too big.");
|
||||
}
|
||||
|
||||
SocialLinkModel socialLink = new SocialLinkModel(socialProvider, username);
|
||||
SocialLinkModel socialLink = new SocialLinkModel(socialProvider, username, username);
|
||||
realm.addSocialLink(user, socialLink);
|
||||
}
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ public class ReadUsersWorker implements Worker {
|
|||
|
||||
// Try to search by social links
|
||||
if (searchBySocialLinks) {
|
||||
SocialLinkModel socialLink = new SocialLinkModel("facebook", username);
|
||||
SocialLinkModel socialLink = new SocialLinkModel("facebook", username, username);
|
||||
realm.getUserBySocialLink(socialLink);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue