Commit c6ef842a authored by benjamin.ertl's avatar benjamin.ertl

v0.1

parent 58d8e322
......@@ -9,9 +9,7 @@
package edu.kit.scc;
import java.text.ParseException;
import java.util.Arrays;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -23,6 +21,7 @@ import com.nimbusds.oauth2.sdk.token.AccessToken;
import com.nimbusds.openid.connect.sdk.claims.UserInfo;
import com.nimbusds.openid.connect.sdk.token.OIDCTokens;
import edu.kit.scc.http.HttpResponse;
import edu.kit.scc.oidc.OidcClient;
import edu.kit.scc.scim.ScimClient;
import edu.kit.scc.scim.ScimUser;
......@@ -40,8 +39,9 @@ public class IdentityHarmonizer {
private OidcClient oidcClient;
public ScimUser harmonizeIdentities(String username, OIDCTokens tokens) {
ScimUser scimUser = new ScimUser();
scimUser.setUserName(username);
ScimUser scimUser = scimClient.getScimUser(username);
ScimUser scimUserFromJWT = null;
ScimUserAttributeMapper mapper = new ScimUserAttributeMapper();
// OIDC
log.debug("Try to get OIDC user information");
......@@ -52,62 +52,34 @@ public class IdentityHarmonizer {
JWTClaimsSet claimsSet = jwt.getJWTClaimsSet();
log.debug("Claims set {}", claimsSet.toJSONObject().toJSONString());
AccessToken accessToken = tokens.getAccessToken();
userInfo = oidcClient.requestUserInfo(accessToken.getValue(), claimsSet);
if (userInfo != null) {
log.debug("User info {}", userInfo.toJSONObject().toJSONString());
ScimUserAttributeMapper attributeMapper = new ScimUserAttributeMapper();
scimUser = attributeMapper.mapFromUserInfo(userInfo);
scimUser.setSchemas(Arrays.asList(scimUser.USER_SCHEMA));
}
} catch (ParseException e) {
log.error(e.getMessage());
}
}
if (scimUser.getUserName() != null && !scimUser.getUserName().equals(username)) {
log.warn("provided username {} does not equal oidc username {}", username, scimUser.getUserName());
// the google case ..
if (scimUser.getEmails() != null && !scimUser.getEmails().isEmpty()) {
String emailAddress = scimUser.getEmails().get(0).getValue();
String[] scopedEmail = emailAddress.split("@");
try {
String userId = scopedEmail[0];
log.warn("overwrite username {} with {}", scimUser.getUserName(), userId);
scimUser.setUserName(userId);
} catch (Exception e) {
log.warn("ERROR parsing email {}", e.getMessage());
}
}
} else {
log.warn("provided username {} does not equal oidc subject {}", username, scimUser.getExternalId());
log.warn("overwrite username {} with {}", username, scimUser.getExternalId());
scimUser.setUserName(scimUser.getExternalId());
}
// SCIM
log.debug("Try to get SCIM user information");
JSONObject userJson = scimClient.getUser(scimUser.getUserName());
if (userJson != null) {
log.debug("SCIM user info {}", userJson.toString());
if (userInfo != null) {
log.debug("User info {}", userInfo.toJSONObject().toJSONString());
scimUserFromJWT = mapper.mapFromUserInfo(userInfo);
}
// LDAP
// TODO
// REGAPP
// TODO
return mapper.merge(scimUser, scimUserFromJWT);
}
// TODO merge
// Example Reg-App HttpResponse
// {"eppn":"ym0762@partner.kit.edu","last_update":"2016-02-02
// 11:47:49.489","email":"ym0762@partner.kit.edu"}
public ScimUser harmonizeIdentities(String username, HttpResponse regAppQuery) {
ScimUser scimUser = scimClient.getScimUser(username);
ScimUser scimUserFromQuery = null;
ScimUserAttributeMapper mapper = new ScimUserAttributeMapper();
if (regAppQuery != null) {
log.debug("Reg-app query response {}", regAppQuery.toString());
scimUserFromQuery = mapper.mapFromRegAppQuery(regAppQuery.getResponseString());
}
log.debug("Aggregated SCIM user information {}", scimUser.toString());
return scimUser;
return mapper.merge(scimUser, scimUserFromQuery);
}
}
......@@ -8,9 +8,6 @@
*/
package edu.kit.scc;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import javax.ws.rs.FormParam;
import org.apache.commons.codec.binary.Base64;
......@@ -29,6 +26,7 @@ import org.springframework.web.bind.annotation.RestController;
import com.nimbusds.openid.connect.sdk.token.OIDCTokens;
import edu.kit.scc.http.HttpResponse;
import edu.kit.scc.oidc.OidcClient;
import edu.kit.scc.regapp.RegAppClient;
import edu.kit.scc.scim.ScimUser;
......@@ -39,10 +37,10 @@ public class RestServiceController {
private static Logger log = LoggerFactory.getLogger(RestServiceController.class);
@Value("${regapp.serviceUsername}")
@Value("${rest.serviceUsername}")
private String restUser;
@Value("${regapp.servicePassword}")
@Value("${rest.servicePassword}")
private String restPassword;
@Autowired
......@@ -68,37 +66,33 @@ public class RestServiceController {
log.debug("Request body {}", body);
boolean regAppSuccess = false;
boolean oidcSuccess = false;
// REG-APP
log.debug("Try reg-app authentication");
boolean regAppSuccess = regAppClient.authenticate(regId, body);
log.debug("Reg-app success {}", regAppSuccess);
regAppSuccess = regAppClient.authenticate(regId, body);
log.debug("Reg-app authentication {}", regAppSuccess);
// OIDC
boolean oidcSuccess = false;
HttpResponse regAppQuery = null;
OIDCTokens tokens = null;
if (!regAppSuccess) {
log.debug("Try OIDC authentication");
try {
log.debug("Got token {}", password);
tokens = oidcClient.requestTokens(URLDecoder.decode(password, "UTF-8"));
if (tokens != null) {
log.debug("OIDC authentication success");
oidcSuccess = true;
}
} catch (ArrayIndexOutOfBoundsException e) {
log.error(e.getMessage());
throw new UnauthorizedException();
} catch (UnsupportedEncodingException e) {
log.error(e.getMessage());
throw new UnauthorizedException();
}
if (regAppSuccess) {
regAppQuery = regAppClient.attributeQuery(regId);
return identityHarmonizer.harmonizeIdentities(username, regAppQuery);
}
log.debug("OIDC success {}", oidcSuccess);
if (regAppSuccess || oidcSuccess) {
// OIDC
log.debug("Try OIDC authentication");
log.debug("Got token {}", password);
tokens = oidcClient.requestTokens(password);
if (tokens != null) {
oidcSuccess = true;
log.debug("OIDC authentication {}", oidcSuccess);
return identityHarmonizer.harmonizeIdentities(username, tokens);
}
log.debug("OIDC authentication {}", oidcSuccess);
// if nothing succeeded, fail ... gracefully
throw new UnauthorizedException();
......
/* Copyright 2016 Karlsruhe Institute of Technology (KIT)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
*/
package edu.kit.scc.regapp;
import org.slf4j.Logger;
......@@ -28,12 +36,34 @@ public class RegAppClient {
public boolean authenticate(String regId, String credentials) {
String regAppUrl = serviceUrl.replaceAll("/$", "");
regAppUrl += "/" + regId;
HttpResponse response = httpClient.makeHttpPostRequest(restUser, restPassword, credentials, regAppUrl);
regAppUrl += "/ecp/regid/" + regId;
HttpResponse response = null;
if (serviceUrl.startsWith("https")) {
response = httpClient.makeHttpsPostRequest(restUser, restPassword, credentials, regAppUrl);
} else {
response = httpClient.makeHttpPostRequest(restUser, restPassword, credentials, regAppUrl);
}
if (response != null && response.statusCode == 200) {
log.debug("Reg-app authentication success");
log.debug("Reg-app authentication success {}", response.toString());
return true;
}
return false;
}
public HttpResponse attributeQuery(String regId) {
String regAppUrl = serviceUrl.replaceAll("/$", "");
regAppUrl += "/attrq/regid/" + regId;
HttpResponse response = null;
if (serviceUrl.startsWith("https")) {
response = httpClient.makeHttpsGetRequest(restUser, restPassword, regAppUrl);
} else {
response = httpClient.makeHttpGetRequest(restUser, restPassword, regAppUrl);
}
if (response != null)
log.debug(response.toString());
return response;
}
}
......@@ -11,12 +11,15 @@ package edu.kit.scc.scim;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.kit.scc.http.HttpClient;
import edu.kit.scc.http.HttpResponse;
......@@ -98,7 +101,7 @@ public class ScimClient {
*
* @return a {@link JSONObject} with the SCIM group information
*/
public JSONObject getGroups(String user, String password) {
public JSONObject getGroups() {
JSONObject json = null;
HttpClient client = new HttpClient();
String url = groupEndpoint.replaceAll("/$", "");
......@@ -113,4 +116,53 @@ public class ScimClient {
return json;
}
/**
* Gets all user information from the SCIM provider.
*
* @param username
* the user's username
* @return a {@link ScimUser} with the SCIM user information
* urn:ietf:params:scim:schemas:core:2.0:User formatted
*/
public ScimUser getScimUser(String username) {
ScimUser scimUser = new ScimUser();
log.debug("Try to get SCIM user information");
JSONObject scimJson = getUser(username);
try {
log.debug("Got SCIM {}", scimJson.toString());
JSONArray schemas = scimJson.getJSONArray("schemas");
if (schemas != null && schemas.length() > 0) {
String schema = schemas.getString(0);
ObjectMapper mapper = new ObjectMapper();
if (schema.equals(scimUser.CORE_SCHEMA_1_0)) {
JSONArray resources = scimJson.getJSONArray("Resources");
JSONObject scim1Json = resources.getJSONObject(0);
log.debug("{} {}", scimUser.CORE_SCHEMA_1_0, scim1Json.toString());
ScimUser1_0 scim1User = mapper.readValue(scim1Json.toString(), ScimUser1_0.class);
ScimUserAttributeMapper attributeMapper = new ScimUserAttributeMapper();
scimUser = attributeMapper.mapFromScim1User(scim1User);
}
if (schema.equals(scimUser.USER_SCHEMA_2_0)) {
log.debug("{} {}", scimUser.USER_SCHEMA_2_0, scimJson.toString());
scimUser = mapper.readValue(scimJson.toString(), ScimUser.class);
}
}
} catch (Exception e) {
log.warn("ERROR {}", e.getMessage());
scimUser = null;
}
return scimUser;
}
}
......@@ -342,7 +342,10 @@ public class ScimUser {
}
@JsonIgnore
public final String USER_SCHEMA = "urn:ietf:params:scim:schemas:core:2.0:User";
public final String CORE_SCHEMA_1_0 = "urn:scim:schemas:core:1.0";
@JsonIgnore
public final String USER_SCHEMA_2_0 = "urn:ietf:params:scim:schemas:core:2.0:User";
private List<String> schemas;
private String id, externalId, userName, displayName, nickName, profileUrl, userType, title, preferredLanguage,
......
/* Copyright 2016 Karlsruhe Institute of Technology (KIT)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
*/
package edu.kit.scc.scim;
import java.util.HashMap;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ScimUser1_0 {
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class Name {
private String familyName, givenName;
public String getFamilyName() {
return familyName;
}
public void setFamilyName(String familyName) {
this.familyName = familyName;
}
public String getGivenName() {
return givenName;
}
public void setGivenName(String givenName) {
this.givenName = givenName;
}
@Override
public String toString() {
return "Name [" + (familyName != null ? "familyName=" + familyName + ", " : "")
+ (givenName != null ? "givenName=" + givenName : "") + "]";
}
}
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class Group {
private String value, display;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getDisplay() {
return display;
}
public void setDisplay(String display) {
this.display = display;
}
@Override
public String toString() {
return "Group [" + (value != null ? "value=" + value + ", " : "")
+ (display != null ? "display=" + display : "") + "]";
}
}
public static class Meta extends HashMap<String, String> {
/**
*
*/
private static final long serialVersionUID = 1L;
}
private String id, userName;
private List<String> emails;
private Name name;
private List<Group> groups;
private Meta meta;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public List<String> getEmails() {
return emails;
}
public void setEmails(List<String> emails) {
this.emails = emails;
}
public Name getName() {
return name;
}
public void setName(Name name) {
this.name = name;
}
public List<Group> getGroups() {
return groups;
}
public void setGroups(List<Group> groups) {
this.groups = groups;
}
public Meta getMeta() {
return meta;
}
public void setMeta(Meta meta) {
this.meta = meta;
}
@Override
public String toString() {
return "ScimUser1_0 [" + (id != null ? "id=" + id + ", " : "")
+ (userName != null ? "userName=" + userName + ", " : "")
+ (emails != null ? "emails=" + emails + ", " : "") + (name != null ? "name=" + name + ", " : "")
+ (groups != null ? "groups=" + groups + ", " : "") + (meta != null ? "meta=" + meta : "") + "]";
}
}
......@@ -10,15 +10,24 @@ package edu.kit.scc.scim;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map.Entry;
import javax.mail.internet.InternetAddress;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.nimbusds.oauth2.sdk.id.Subject;
import com.nimbusds.openid.connect.sdk.claims.UserInfo;
import edu.kit.scc.scim.ScimUser.Address;
import edu.kit.scc.scim.ScimUser.Email;
import edu.kit.scc.scim.ScimUser.Group;
import edu.kit.scc.scim.ScimUser.Meta;
import edu.kit.scc.scim.ScimUser.Name;
import edu.kit.scc.scim.ScimUser.PhoneNumber;
......@@ -26,8 +35,48 @@ import edu.kit.scc.scim.ScimUser.Photo;
public class ScimUserAttributeMapper {
private static final Logger log = LoggerFactory.getLogger(ScimUserAttributeMapper.class);
public ScimUser mapFromRegAppQuery(String query) {
ScimUser scimUser = new ScimUser();
scimUser.setSchemas(Arrays.asList(scimUser.USER_SCHEMA_2_0));
try {
JSONObject jsonQuery = new JSONObject(query);
String eppn = jsonQuery.getString("eppn");
if (eppn != null) {
String userName = eppn.split("@")[0];
scimUser.setUserName(userName);
}
String mail = jsonQuery.getString("mail");
if (mail != null) {
if (scimUser.getEmails() == null)
scimUser.setEmails(new ArrayList<Email>());
Email email = new Email();
email.setValue(mail);
scimUser.getEmails().add(email);
}
String lastUpdate = jsonQuery.getString("last_update");
if (lastUpdate != null) {
if (scimUser.getMeta() == null)
scimUser.setMeta(new Meta());
scimUser.getMeta().put("lastModified", lastUpdate);
}
} catch (JSONException e) {
} catch (ArrayIndexOutOfBoundsException e) {
}
return scimUser;
}
public ScimUser mapFromUserInfo(UserInfo userInfo) {
ScimUser scimUser = new ScimUser();
scimUser.setSchemas(Arrays.asList(scimUser.USER_SCHEMA_2_0));
com.nimbusds.openid.connect.sdk.claims.Address address = userInfo.getAddress();
if (address != null) {
......@@ -126,4 +175,103 @@ public class ScimUserAttributeMapper {
return scimUser;
}
public ScimUser mapFromScim1User(ScimUser1_0 scim1User) {
ScimUser scimUser = new ScimUser();
scimUser.setSchemas(Arrays.asList(scimUser.USER_SCHEMA_2_0));
List<String> emails = scim1User.getEmails();
if (emails != null) {
if (scimUser.getEmails() == null)
scimUser.setEmails(new ArrayList<Email>());
for (String email : emails) {
Email newEmail = new Email();
newEmail.setValue(email);
scimUser.getEmails().add(newEmail);
}
}
List<edu.kit.scc.scim.ScimUser1_0.Group> groups = scim1User.getGroups();
if (groups != null) {
if (scimUser.getGroups() == null)
scimUser.setGroups(new ArrayList<Group>());
for (edu.kit.scc.scim.ScimUser1_0.Group group : groups) {
Group newGroup = new Group();
newGroup.setDisplay(group.getDisplay());
newGroup.setValue(group.getValue());
scimUser.getGroups().add(newGroup);
}
}
String id = scim1User.getId();
if (id != null)
scimUser.setId(id);
edu.kit.scc.scim.ScimUser1_0.Meta meta = scim1User.getMeta();
if (meta != null) {
if (scimUser.getMeta() == null)
scimUser.setMeta(new Meta());
for (Entry<String, String> entry : meta.entrySet()) {