Add Zenodo Login and the ability to use it's access token for DOI creation

This commit is contained in:
George Kalampokis 2020-04-03 18:40:03 +03:00
parent be6227a81d
commit f39c113b7b
29 changed files with 518 additions and 20 deletions

View File

@ -22,6 +22,9 @@ import eu.eudat.logic.security.validators.orcid.ORCIDTokenValidator;
import eu.eudat.logic.security.validators.orcid.helpers.ORCIDRequest;
import eu.eudat.logic.security.validators.orcid.helpers.ORCIDResponseToken;
import eu.eudat.logic.security.validators.twitter.TwitterTokenValidator;
import eu.eudat.logic.security.validators.zenodo.ZenodoTokenValidator;
import eu.eudat.logic.security.validators.zenodo.helpers.ZenodoRequest;
import eu.eudat.logic.security.validators.zenodo.helpers.ZenodoResponseToken;
import eu.eudat.logic.services.operations.authentication.AuthenticationService;
import eu.eudat.models.data.helpers.responses.ResponseItem;
import eu.eudat.models.data.login.Credentials;
@ -54,28 +57,34 @@ public class Login {
private LinkedInTokenValidator linkedInTokenValidator;
private OpenAIRETokenValidator openAIRETokenValidator;
private ConfigurableProviderTokenValidator configurableProviderTokenValidator;
private ZenodoTokenValidator zenodoTokenValidator;
private ConfigLoader configLoader;
// private Logger logger;
private UserManager userManager;
@Autowired
public Login(CustomAuthenticationProvider customAuthenticationProvider, AuthenticationService nonVerifiedUserAuthenticationService,
TwitterTokenValidator twitterTokenValidator, LinkedInTokenValidator linkedInTokenValidator, B2AccessTokenValidator b2AccessTokenValidator,
ORCIDTokenValidator orcidTokenValidator, OpenAIRETokenValidator openAIRETokenValidator, ConfigurableProviderTokenValidator configurableProviderTokenValidator, ConfigLoader configLoader, UserManager userManager/*, Logger logger*/) {
public Login(CustomAuthenticationProvider customAuthenticationProvider,
AuthenticationService nonVerifiedUserAuthenticationService, TwitterTokenValidator twitterTokenValidator,
B2AccessTokenValidator b2AccessTokenValidator, ORCIDTokenValidator orcidTokenValidator,
LinkedInTokenValidator linkedInTokenValidator, OpenAIRETokenValidator openAIRETokenValidator,
ConfigurableProviderTokenValidator configurableProviderTokenValidator, ZenodoTokenValidator zenodoTokenValidator,
ConfigLoader configLoader, UserManager userManager) {
this.customAuthenticationProvider = customAuthenticationProvider;
this.nonVerifiedUserAuthenticationService = nonVerifiedUserAuthenticationService;
this.twitterTokenValidator = twitterTokenValidator;
this.linkedInTokenValidator = linkedInTokenValidator;
this.b2AccessTokenValidator = b2AccessTokenValidator;
this.orcidTokenValidator = orcidTokenValidator;
this.linkedInTokenValidator = linkedInTokenValidator;
this.openAIRETokenValidator = openAIRETokenValidator;
this.configurableProviderTokenValidator = configurableProviderTokenValidator;
this.zenodoTokenValidator = zenodoTokenValidator;
this.configLoader = configLoader;
// this.logger = logger;
this.userManager = userManager;
}
@Transactional
@RequestMapping(method = RequestMethod.POST, value = {"/externallogin"}, consumes = "application/json", produces = "application/json")
public @ResponseBody
@ -128,6 +137,12 @@ public class Login {
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<ConfigurableProviderResponseToken>().payload(this.configurableProviderTokenValidator.getAccessToken(configurableProviderRequest)).status(ApiMessageCode.NO_MESSAGE));
}
@RequestMapping(method = RequestMethod.POST, value = {"/zenodoRequestToken"}, produces = "application/json", consumes = "application/json")
public @ResponseBody
ResponseEntity<ResponseItem<ZenodoResponseToken>> ZenodoRequestToken(@RequestBody ZenodoRequest zenodoRequest) {
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<ZenodoResponseToken>().payload(this.zenodoTokenValidator.getAccessToken(zenodoRequest)).status(ApiMessageCode.NO_MESSAGE));
}
@RequestMapping(method = RequestMethod.POST, value = {"/me"}, consumes = "application/json", produces = "application/json")
public @ResponseBody
ResponseEntity<ResponseItem<Principal>> authMe(Principal principal) throws NullEmailException {

View File

@ -4,6 +4,7 @@ import eu.eudat.logic.builders.Builder;
import eu.eudat.models.data.security.Principal;
import eu.eudat.types.Authorities;
import java.time.Instant;
import java.util.Date;
import java.util.Set;
import java.util.UUID;
@ -22,6 +23,8 @@ public class PrincipalBuilder extends Builder<Principal> {
private String culture;
private String language;
private String timezone;
private String zenodoToken;
private Instant zenodoDuration;
public PrincipalBuilder id(UUID id) {
this.id = id;
@ -68,6 +71,16 @@ public class PrincipalBuilder extends Builder<Principal> {
return this;
}
public PrincipalBuilder zenodoToken(String zenodoToken) {
this.zenodoToken = zenodoToken;
return this;
}
public PrincipalBuilder zenodoDuration(Instant zenodoDuration) {
this.zenodoDuration = zenodoDuration;
return this;
}
@Override
public Principal build() {
Principal principal = new Principal();
@ -80,6 +93,8 @@ public class PrincipalBuilder extends Builder<Principal> {
principal.setCulture(culture);
principal.setLanguage(language);
principal.setTimezone(timezone);
principal.setZenodoToken(zenodoToken);
principal.setZenodoDuration(zenodoDuration);
return principal;
}
}

View File

@ -1599,6 +1599,7 @@ public class DataManagementPlanManager {
if (dmp.getDoi() != null)
throw new Exception("DMP already has a DOI");
String zenodoToken = principal.getZenodoToken() != null && !principal.getZenodoToken().isEmpty() ? principal.getZenodoToken() : this.environment.getProperty("zenodo.access_token");
// First step, post call to Zenodo, to create the entry.
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
@ -1623,34 +1624,34 @@ public class DataManagementPlanManager {
String previousDOI = this.getPreviousDOI(dmp.getGroupId(), dmp.getId());
try {
if (previousDOI == null) {
String createUrl = this.environment.getProperty("zenodo.url") + "deposit/depositions" + "?access_token=" + this.environment.getProperty("zenodo.access_token");
String createUrl = this.environment.getProperty("zenodo.url") + "deposit/depositions" + "?access_token=" + zenodoToken;
createResponse = restTemplate.postForEntity(createUrl, request, Map.class).getBody();
links = (LinkedHashMap<String, String>) createResponse.get("links");
} else {
//It requires more than one step to create a new version
//First, get the deposit related to the concept DOI
String listUrl = this.environment.getProperty("zenodo.url") + "deposit/depositions" + "?q=conceptdoi:\"" + previousDOI + "\"&access_token=" + this.environment.getProperty("zenodo.access_token");
String listUrl = this.environment.getProperty("zenodo.url") + "deposit/depositions" + "?q=conceptdoi:\"" + previousDOI + "\"&access_token=" + zenodoToken;
ResponseEntity<Map[]> listResponses = restTemplate.getForEntity(listUrl, Map[].class);
createResponse = listResponses.getBody()[0];
links = (LinkedHashMap<String, String>) createResponse.get("links");
//Second, make the new version (not in the links?)
String newVersionUrl = links.get("self") + "/actions/newversion" + "?access_token=" + this.environment.getProperty("zenodo.access_token");
String newVersionUrl = links.get("self") + "/actions/newversion" + "?access_token=" + zenodoToken;
createResponse = restTemplate.postForObject(newVersionUrl, null, Map.class);
links = (LinkedHashMap<String, String>) createResponse.get("links");
//Third, get the new deposit
String latestDraftUrl = links.get("latest_draft") + "?access_token=" + this.environment.getProperty("zenodo.access_token");
String latestDraftUrl = links.get("latest_draft") + "?access_token=" + zenodoToken;
createResponse = restTemplate.getForObject(latestDraftUrl, Map.class);
links = (LinkedHashMap<String, String>) createResponse.get("links");
//At this point it might fail to perform the next requests so enclose them with try catch
try {
//Forth, update the new deposit's metadata
String updateUrl = links.get("self") + "?access_token=" + this.environment.getProperty("zenodo.access_token");
String updateUrl = links.get("self") + "?access_token=" + zenodoToken;
restTemplate.put(updateUrl, request);
//And finally remove pre-existing files from it
String fileListUrl = links.get("self") + "/files" + "?access_token=" + this.environment.getProperty("zenodo.access_token");
String fileListUrl = links.get("self") + "/files" + "?access_token=" + zenodoToken;
ResponseEntity<Map[]> fileListResponse = restTemplate.getForEntity(fileListUrl, Map[].class);
for (Map file : fileListResponse.getBody()) {
String fileDeleteUrl = links.get("self") + "/files/" + file.get("id") + "?access_token=" + this.environment.getProperty("zenodo.access_token");
String fileDeleteUrl = links.get("self") + "/files/" + file.get("id") + "?access_token=" + zenodoToken;
restTemplate.delete(fileDeleteUrl);
}
}catch (Exception e) {

View File

@ -0,0 +1,8 @@
package eu.eudat.logic.security.customproviders.Zenodo;
import eu.eudat.logic.security.validators.orcid.helpers.ORCIDResponseToken;
import eu.eudat.logic.security.validators.zenodo.helpers.ZenodoResponseToken;
public interface ZenodoCustomProvider {
ZenodoResponseToken getAccessToken(String code, String clientId, String clientSecret, String redirectUri);
}

View File

@ -0,0 +1,72 @@
package eu.eudat.logic.security.customproviders.Zenodo;
import com.fasterxml.jackson.databind.ObjectMapper;
import eu.eudat.logic.security.validators.orcid.helpers.ORCIDResponseToken;
import eu.eudat.logic.security.validators.zenodo.helpers.ZenodoResponseToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
@Component("ZenodoCustomProvider")
public class ZenodoCustomProviderImpl implements ZenodoCustomProvider {
private static final Logger logger = LoggerFactory.getLogger(ZenodoCustomProviderImpl.class);
private Environment environment;
@Autowired
public ZenodoCustomProviderImpl(Environment environment) {
this.environment = environment;
}
@Override
public ZenodoResponseToken getAccessToken(String code, String clientId, String clientSecret, String redirectUri) {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("client_id", clientId);
map.add("client_secret", clientSecret);
map.add("grant_type", "authorization_code");
map.add("code", code);
map.add("redirect_uri", redirectUri);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
try {
Map<String, Object> values = restTemplate.postForObject(this.environment.getProperty("zenodo.login.access_token_url"), request, Map.class);
ZenodoResponseToken zenodoResponseToken = new ZenodoResponseToken();
Map<String, Object> user = (Map<String, Object>) values.get("user");
zenodoResponseToken.setUserId((String) user.get("id"));
zenodoResponseToken.setEmail((String) user.get("email"));
zenodoResponseToken.setExpiresIn((Integer) values.get("expires_in"));
zenodoResponseToken.setAccessToken((String) values.get("access_token"));
return zenodoResponseToken;
} catch (HttpClientErrorException ex) {
logger.error(ex.getResponseBodyAsString(), ex);
}
return null;
}
private HttpHeaders createBearerAuthHeaders(String accessToken) {
return new HttpHeaders() {{
String authHeader = "Bearer " + accessToken;
set("Authorization", authHeader);
}};
}
}

View File

@ -0,0 +1,49 @@
package eu.eudat.logic.security.customproviders.Zenodo;
import java.util.Map;
public class ZenodoUser {
private String userId;
private String email;
private String accessToken;
private Integer expiresIn;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public Integer getExpiresIn() {
return expiresIn;
}
public void setExpiresIn(Integer expiresIn) {
this.expiresIn = expiresIn;
}
public ZenodoUser getZenodoUser(Object data) {
this.userId = (String) ((Map) data).get("userId");
this.email = (String) ((Map) data).get("email");
this.accessToken = (String) ((Map) data).get("accessToken");
this.expiresIn = (Integer) ((Map) data).get("expiresIn");
return this;
}
}

View File

@ -6,6 +6,7 @@ import eu.eudat.logic.security.customproviders.ConfigurableProvider.Configurable
import eu.eudat.logic.security.customproviders.LinkedIn.LinkedInCustomProvider;
import eu.eudat.logic.security.customproviders.ORCID.ORCIDCustomProvider;
import eu.eudat.logic.security.customproviders.OpenAIRE.OpenAIRECustomProvider;
import eu.eudat.logic.security.customproviders.Zenodo.ZenodoCustomProvider;
import eu.eudat.logic.security.validators.b2access.B2AccessTokenValidator;
import eu.eudat.logic.security.validators.configurableProvider.ConfigurableProviderTokenValidator;
import eu.eudat.logic.security.validators.facebook.FacebookTokenValidator;
@ -14,6 +15,7 @@ import eu.eudat.logic.security.validators.linkedin.LinkedInTokenValidator;
import eu.eudat.logic.security.validators.openaire.OpenAIRETokenValidator;
import eu.eudat.logic.security.validators.orcid.ORCIDTokenValidator;
import eu.eudat.logic.security.validators.twitter.TwitterTokenValidator;
import eu.eudat.logic.security.validators.zenodo.ZenodoTokenValidator;
import eu.eudat.logic.services.operations.authentication.AuthenticationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
@ -23,7 +25,7 @@ import org.springframework.stereotype.Service;
@Service("tokenValidatorFactory")
public class TokenValidatorFactoryImpl implements TokenValidatorFactory {
public enum LoginProvider {
GOOGLE(1), FACEBOOK(2), TWITTER(3), LINKEDIN(4), NATIVELOGIN(5), B2_ACCESS(6), ORCID(7), OPENAIRE(8), CONFIGURABLE(9);
GOOGLE(1), FACEBOOK(2), TWITTER(3), LINKEDIN(4), NATIVELOGIN(5), B2_ACCESS(6), ORCID(7), OPENAIRE(8), CONFIGURABLE(9), ZENODO(10);
private int value;
@ -55,6 +57,8 @@ public class TokenValidatorFactoryImpl implements TokenValidatorFactory {
return OPENAIRE;
case 9:
return CONFIGURABLE;
case 10:
return ZENODO;
default:
throw new RuntimeException("Unsupported LoginProvider");
}
@ -69,12 +73,15 @@ public class TokenValidatorFactoryImpl implements TokenValidatorFactory {
private OpenAIRECustomProvider openAIRECustomProvider;
private ConfigurableProviderCustomProvider configurableProviderCustomProvider;
private ConfigLoader configLoader;
private ZenodoCustomProvider zenodoCustomProvider;
@Autowired
public TokenValidatorFactoryImpl(
Environment environment,
AuthenticationService nonVerifiedUserAuthenticationService, B2AccessCustomProvider b2AccessCustomProvider,
ORCIDCustomProvider orcidCustomProvider, LinkedInCustomProvider linkedInCustomProvider, OpenAIRECustomProvider openAIRECustomProvider, ConfigurableProviderCustomProvider configurableProviderCustomProvider, ConfigLoader configLoader) {
ORCIDCustomProvider orcidCustomProvider, LinkedInCustomProvider linkedInCustomProvider, OpenAIRECustomProvider openAIRECustomProvider,
ConfigurableProviderCustomProvider configurableProviderCustomProvider, ConfigLoader configLoader,
ZenodoCustomProvider zenodoCustomProvider) {
this.environment = environment;
this.nonVerifiedUserAuthenticationService = nonVerifiedUserAuthenticationService;
this.b2AccessCustomProvider = b2AccessCustomProvider;
@ -83,6 +90,7 @@ public class TokenValidatorFactoryImpl implements TokenValidatorFactory {
this.openAIRECustomProvider = openAIRECustomProvider;
this.configurableProviderCustomProvider = configurableProviderCustomProvider;
this.configLoader = configLoader;
this.zenodoCustomProvider = zenodoCustomProvider;
}
public TokenValidator getProvider(LoginProvider provider) {
@ -103,6 +111,8 @@ public class TokenValidatorFactoryImpl implements TokenValidatorFactory {
return new OpenAIRETokenValidator(this.environment, this.nonVerifiedUserAuthenticationService, this.openAIRECustomProvider);
case CONFIGURABLE:
return new ConfigurableProviderTokenValidator(this.configurableProviderCustomProvider, this.nonVerifiedUserAuthenticationService, this.configLoader);
case ZENODO:
return new ZenodoTokenValidator(this.environment, this.nonVerifiedUserAuthenticationService, this.zenodoCustomProvider);
default:
throw new RuntimeException("Login Provider Not Implemented");
}

View File

@ -0,0 +1,57 @@
package eu.eudat.logic.security.validators.zenodo;
import eu.eudat.exceptions.security.NonValidTokenException;
import eu.eudat.exceptions.security.NullEmailException;
import eu.eudat.logic.security.customproviders.ORCID.ORCIDCustomProvider;
import eu.eudat.logic.security.customproviders.ORCID.ORCIDUser;
import eu.eudat.logic.security.customproviders.Zenodo.ZenodoCustomProvider;
import eu.eudat.logic.security.customproviders.Zenodo.ZenodoUser;
import eu.eudat.logic.security.validators.TokenValidator;
import eu.eudat.logic.security.validators.zenodo.helpers.ZenodoRequest;
import eu.eudat.logic.security.validators.zenodo.helpers.ZenodoResponseToken;
import eu.eudat.logic.services.operations.authentication.AuthenticationService;
import eu.eudat.models.data.login.LoginInfo;
import eu.eudat.models.data.loginprovider.LoginProviderUser;
import eu.eudat.models.data.security.Principal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.security.GeneralSecurityException;
@Component("zenodoTokenValidator")
public class ZenodoTokenValidator implements TokenValidator {
private ZenodoCustomProvider zenodoCustomProvider;
private Environment environment;
private AuthenticationService nonVerifiedUserAuthenticationService;
@Autowired
public ZenodoTokenValidator(Environment environment, AuthenticationService nonVerifiedUserAuthenticationService, ZenodoCustomProvider zenodoCustomProvider) {
this.environment = environment;
this.nonVerifiedUserAuthenticationService = nonVerifiedUserAuthenticationService;
this.zenodoCustomProvider = zenodoCustomProvider;
}
@Override
public Principal validateToken(LoginInfo credentials) throws NonValidTokenException, IOException, GeneralSecurityException, NullEmailException {
ZenodoUser zenodoUser = new ZenodoUser().getZenodoUser(credentials.getData());
LoginProviderUser user = new LoginProviderUser();
user.setId(zenodoUser.getUserId());
user.setName(zenodoUser.getEmail());
user.setEmail(zenodoUser.getEmail());
user.setZenodoId(zenodoUser.getAccessToken());
user.setZenodoExpire(zenodoUser.getExpiresIn());
user.setProvider(credentials.getProvider());
user.setSecret(credentials.getTicket());
return this.nonVerifiedUserAuthenticationService.Touch(user);
}
public ZenodoResponseToken getAccessToken(ZenodoRequest zenodoRequest) {
return this.zenodoCustomProvider.getAccessToken(zenodoRequest.getCode()
, this.environment.getProperty("zenodo.login.client_id")
, this.environment.getProperty("zenodo.login.client_secret")
, this.environment.getProperty("zenodo.login.redirect_uri"));
}
}

View File

@ -0,0 +1,12 @@
package eu.eudat.logic.security.validators.zenodo.helpers;
public class ZenodoRequest {
private String code;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}

View File

@ -0,0 +1,38 @@
package eu.eudat.logic.security.validators.zenodo.helpers;
public class ZenodoResponseToken {
private String userId;
private String email;
private Integer expiresIn;
private String accessToken;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getExpiresIn() {
return expiresIn;
}
public void setExpiresIn(Integer expiresIn) {
this.expiresIn = expiresIn;
}
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
}

View File

@ -20,6 +20,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;
import org.springframework.transaction.annotation.Transactional;
import java.time.Instant;
import java.util.*;
public abstract class AbstractAuthenticationService implements AuthenticationService {
@ -132,7 +133,7 @@ public abstract class AbstractAuthenticationService implements AuthenticationSer
userInfo = this.apiContext.getOperationsContext().getBuilderFactory().getBuilder(UserInfoBuilder.class)
.name(profile.getName()).verified_email(profile.getIsVerified())
.email(profile.getEmail()).created(new Date()).lastloggedin(new Date())
.additionalinfo("{\"data\":{\"avatar\":{\"url\":\"" + profile.getAvatarUrl() + "\"}}}")
.additionalinfo("{\"data\":{\"avatar\":{\"url\":\"" + profile.getAvatarUrl() + "\"}},{\"zenodoToken\":\"" + profile.getZenodoId() + "\", \"expirationDate\": \"" + Instant.now().plusSeconds(profile.getZenodoExpire()).toEpochMilli() + "\"}")
.authorization_level((short) 1).usertype((short) 1)
.build();
@ -149,7 +150,15 @@ public abstract class AbstractAuthenticationService implements AuthenticationSer
} else {
Map<String, Object> additionalInfo = userInfo.getAdditionalinfo() != null ?
new JSONObject(userInfo.getAdditionalinfo()).toMap() : new HashMap<>();
additionalInfo.put("avatarUrl", profile.getAvatarUrl());
if (profile.getAvatarUrl() != null && !profile.getAvatarUrl().isEmpty() && !profile.getAvatarUrl().equals("null")) {
additionalInfo.put("avatarUrl", profile.getAvatarUrl());
}
if (profile.getZenodoId() != null && !profile.getZenodoId().isEmpty() && !profile.getZenodoId().equals("null")) {
additionalInfo.put("zenodoToken", profile.getZenodoId());
}
if (profile.getZenodoExpire() != null) {
additionalInfo.put("expirationDate", Instant.now().plusSeconds(profile.getZenodoExpire()).toEpochMilli());
}
userInfo.setLastloggedin(new Date());
userInfo.setAdditionalinfo(new JSONObject(additionalInfo).toString());
Set<Credential> credentials = userInfo.getCredentials();

View File

@ -11,6 +11,7 @@ import eu.eudat.types.Authorities;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import java.time.Instant;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
@ -33,6 +34,18 @@ public class NonVerifiedUserEmailAuthenticationService extends AbstractAuthentic
} catch (Exception e) {
avatarUrl = "";
}
String zenodoToken;
try {
zenodoToken = user.getAdditionalinfo() != null ? new ObjectMapper().readTree(user.getAdditionalinfo()).get("zenodoToken").asText() : "";
} catch (Exception e) {
zenodoToken = "";
}
Instant zenodoDuration;
try {
zenodoDuration = user.getAdditionalinfo() != null ? Instant.ofEpochMilli(new ObjectMapper().readTree(user.getAdditionalinfo()).get("expirationDate").asLong()) : Instant.now();
} catch (Exception e) {
zenodoDuration = Instant.now();
}
String culture;
try {
culture = user.getAdditionalinfo() != null ? new ObjectMapper().readTree(user.getAdditionalinfo()).get("culture").get("name").asText() : "";
@ -58,6 +71,8 @@ public class NonVerifiedUserEmailAuthenticationService extends AbstractAuthentic
.culture(culture)
.language(language)
.timezone(timezone)
.zenodoToken(zenodoToken)
.zenodoDuration(zenodoDuration)
.build();
List<UserRole> userRoles = apiContext.getOperationsContext().getDatabaseRepository().getUserRoleDao().getUserRoles(user);

View File

@ -20,6 +20,7 @@ import org.json.JSONObject;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import java.time.Instant;
import java.util.*;
@ -42,6 +43,18 @@ public class VerifiedUserAuthenticationService extends AbstractAuthenticationSer
} catch (Exception e) {
avatarUrl = "";
}
String zenodoToken;
try {
zenodoToken = user.getAdditionalinfo() != null ? new ObjectMapper().readTree(user.getAdditionalinfo()).get("zenodoToken").asText() : "";
} catch (Exception e) {
zenodoToken = "";
}
Instant zenodoDuration;
try {
zenodoDuration = user.getAdditionalinfo() != null ? Instant.ofEpochMilli(new ObjectMapper().readTree(user.getAdditionalinfo()).get("expirationDate").asLong()) : Instant.now();
} catch (Exception e) {
zenodoDuration = Instant.now();
}
String culture;
try {
culture = user.getAdditionalinfo() != null ? new ObjectMapper().readTree(user.getAdditionalinfo()).get("culture").get("name").asText() : "";
@ -67,6 +80,8 @@ public class VerifiedUserAuthenticationService extends AbstractAuthenticationSer
.culture(culture)
.language(language)
.timezone(timezone)
.zenodoToken(zenodoToken)
.zenodoDuration(zenodoDuration)
.build();
List<UserRole> userRoles = apiContext.getOperationsContext().getDatabaseRepository().getUserRoleDao().getUserRoles(user);

View File

@ -11,6 +11,8 @@ public class LoginProviderUser {
private String avatarUrl;
private boolean isVerified;
private TokenValidatorFactoryImpl.LoginProvider provider;
private String zenodoId;
private Integer zenodoExpire;
public String getId() {
return id;
@ -67,4 +69,20 @@ public class LoginProviderUser {
public void setAvatarUrl(String avatarUrl) {
this.avatarUrl = avatarUrl;
}
public String getZenodoId() {
return zenodoId;
}
public void setZenodoId(String zenodoId) {
this.zenodoId = zenodoId;
}
public Integer getZenodoExpire() {
return zenodoExpire;
}
public void setZenodoExpire(Integer zenodoExpire) {
this.zenodoExpire = zenodoExpire;
}
}

View File

@ -3,6 +3,7 @@ package eu.eudat.models.data.security;
import com.fasterxml.jackson.annotation.JsonIgnore;
import eu.eudat.types.Authorities;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;
@ -17,6 +18,8 @@ public class Principal {
private String culture;
private String language;
private String timezone;
private String zenodoToken;
private Instant zenodoDuration;
public UUID getId() {
return id;
@ -86,6 +89,22 @@ public class Principal {
this.timezone = timezone;
}
public String getZenodoToken() {
return zenodoToken;
}
public void setZenodoToken(String zenodoToken) {
this.zenodoToken = zenodoToken;
}
public Instant getZenodoDuration() {
return zenodoDuration;
}
public void setZenodoDuration(Instant zenodoDuration) {
this.zenodoDuration = zenodoDuration;
}
@JsonIgnore
public Set<Authorities> getAuthz() {
return this.authorities;

View File

@ -69,6 +69,10 @@ conf_email.subject=OpenDMP email confirmation
#############ZENODO CONFIGURATIONS#########
zenodo.url=https://sandbox.zenodo.org/api/
zenodo.access_token=
zenodo.login.access_token_url=https://sandbox.zenodo.org/oauth/token
zenodo.login.client_id=
zenodo.login.client_secret=
zenodo.login.redirect_uri=http://localhost:4200/login/external/zenodo
#############CONTACT EMAIL CONFIGURATIONS#########
contact_email.mail=

View File

@ -7,5 +7,6 @@ export enum AuthProvider {
B2Access = 6,
ORCID = 7,
OpenAire = 8,
Configurable = 9
Configurable = 9,
Zenodo = 10
}

View File

@ -42,6 +42,11 @@ export class LoginProviders {
return this._openAireConfiguration;
}
private _zenodoConfiguration: LoginConfiguration;
get zenodoConfiguration(): LoginConfiguration {
return this._zenodoConfiguration;
}
public static parseValue(value: any): LoginProviders {
const obj: LoginProviders = new LoginProviders();
obj._enabled = value.enabled;
@ -52,6 +57,7 @@ export class LoginProviders {
obj._b2accessConfiguration = value.b2accessConfiguration;
obj._orcidConfiguration = value.orcidConfiguration;
obj._openAireConfiguration = value.openAireConfiguration;
obj._zenodoConfiguration = value.zenodoConfiguration;
return obj;
}
}

View File

@ -0,0 +1,6 @@
export class ZenodoToken {
userId: string;
expiresIn: number;
accessToken:string;
email: string;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -54,6 +54,12 @@
</button>
</div>
</div>
<div *ngIf="hasZenodoOauth()" class="col-auto zenodo-logo">
<button class="zenodo-button" mat-icon-button (click)="zenodoLogin()" class="login-social-button">
<span class="zenodoIcon"></span>
<!-- <span></span> -->
</button>
</div>
</div>
<div class="card-footer">
<h4 class="text-uppercase">

View File

@ -156,6 +156,12 @@
height: 90px;
}
.accesss-methods .zenodo-logo {
height: 75px;
padding-top: 8px;
margin-top: 13px;
}
.tip {
margin-top: -20px;
}
@ -231,6 +237,14 @@ span.configurableIcon {
height: 56px;
}
span.zenodoIcon {
background: url(img/zenodo-white-200.png) no-repeat 100px 56px;
background-position: center;
float: right;
width: 150px;
height: 56px;
}
.b2access-button {
margin-top: 10px;
width: fit-content;
@ -251,6 +265,11 @@ span.configurableIcon {
width: fit-content;
}
.zenodo-button {
margin-top: 10px;
width: fit-content;
}
.login-logo {
background: url(img/open-dmp.png) no-repeat;
width: 273px;

View File

@ -78,6 +78,10 @@ export class LoginComponent extends BaseComponent implements OnInit, AfterViewIn
this.router.navigate(['/login/configurable/' + provider.configurableLoginId])
}
public zenodoLogin() {
this.router.navigate(['/login/external/zenodo']);
}
public hasFacebookOauth(): boolean {
return this.hasProvider(AuthProvider.Facebook);
}
@ -106,6 +110,10 @@ export class LoginComponent extends BaseComponent implements OnInit, AfterViewIn
return this.hasProvider(AuthProvider.OpenAire);
}
public hasZenodoOauth(): boolean {
return this.hasProvider(AuthProvider.Zenodo);
}
public initProviders() {
if (this.hasProvider(AuthProvider.Google)) { this.initializeGoogleOauth(); }
if (this.hasProvider(AuthProvider.Facebook)) { this.initializeFacebookOauth(); }
@ -127,6 +135,7 @@ export class LoginComponent extends BaseComponent implements OnInit, AfterViewIn
case AuthProvider.B2Access: return this.hasAllRequiredFieldsConfigured(this.configurationService.loginProviders.b2accessConfiguration);
case AuthProvider.ORCID: return this.hasAllRequiredFieldsConfigured(this.configurationService.loginProviders.orcidConfiguration);
case AuthProvider.OpenAire: return this.hasAllRequiredFieldsConfigured(this.configurationService.loginProviders.openAireConfiguration);
case AuthProvider.Zenodo: return this.hasAllRequiredFieldsConfigured(this.configurationService.loginProviders.zenodoConfiguration);
default: throw new Error('Unsupported Provider Type');
}
}

View File

@ -12,6 +12,7 @@ import { ConfigurableProvidersService } from '@app/ui/auth/login/utilities/confi
import { LoginService } from '@app/ui/auth/login/utilities/login.service';
import { CommonFormsModule } from '@common/forms/common-forms.module';
import { CommonUiModule } from '@common/ui/common-ui.module';
import { ZenodoLoginComponent } from './zenodo-login/zenodo-login.component';
@NgModule({
imports: [
@ -27,7 +28,8 @@ import { CommonUiModule } from '@common/ui/common-ui.module';
OrcidLoginComponent,
EmailConfirmation,
OpenAireLoginComponent,
ConfigurableLoginComponent
ConfigurableLoginComponent,
ZenodoLoginComponent
],
providers: [LoginService, ConfigurableProvidersService]
})

View File

@ -8,6 +8,7 @@ import { OrcidLoginComponent } from './orcid-login/orcid-login.component';
import { TwitterLoginComponent } from './twitter-login/twitter-login.component';
import { OpenAireLoginComponent } from "./openaire-login/openaire-login.component";
import { ConfigurableLoginComponent } from "./configurable-login/configurable-login.component";
import { ZenodoLoginComponent } from './zenodo-login/zenodo-login.component';
const routes: Routes = [
{ path: '', component: LoginComponent },
@ -18,7 +19,8 @@ const routes: Routes = [
{ path: 'confirmation/:token', component: EmailConfirmation },
{ path: 'confirmation', component: EmailConfirmation },
{ path: 'openaire', component: OpenAireLoginComponent},
{ path: 'configurable/:id', component: ConfigurableLoginComponent}
{ path: 'configurable/:id', component: ConfigurableLoginComponent},
{ path: 'external/zenodo', component: ZenodoLoginComponent }
];
@NgModule({

View File

@ -0,0 +1,85 @@
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { ActivatedRoute, Params } from '@angular/router';
import { AuthProvider } from '@app/core/common/enum/auth-provider';
import { OrcidUser } from '@app/core/model/orcid/orcidUser';
import { AuthService } from '@app/core/services/auth/auth.service';
import { LoginService } from '@app/ui/auth/login/utilities/login.service';
import { BaseComponent } from '@common/base/base.component';
import { environment } from 'environments/environment';
import { takeUntil } from 'rxjs/operators';
import { ConfigurationService } from '@app/core/services/configuration/configuration.service';
import { ZenodoToken } from '@app/core/model/zenodo/zenodo-token.model';
@Component({
selector: 'app-zenodo-login',
templateUrl: './zenodo-login.component.html',
styleUrls: ['./zenodo-login.component.scss']
})
export class ZenodoLoginComponent extends BaseComponent implements OnInit {
private returnUrl: string;
private zenodoToken: ZenodoToken
private accessToken: string;
private emailFormControl = new FormControl('');
constructor(
private route: ActivatedRoute,
private authService: AuthService,
private loginService: LoginService,
private httpClient: HttpClient,
private configurationService: ConfigurationService
) {
super();
this.zenodoToken = new ZenodoToken;
}
ngOnInit(): void {
this.route.queryParams
.pipe(takeUntil(this._destroyed))
.subscribe((params: Params) => {
const returnUrl = params['returnUrl'];
if (returnUrl) { this.returnUrl = returnUrl; }
if (!params['code']) { this.zenodoAccessGetAuthCode(); } else { this.zenodoLogin(params['code']); }
});
}
public zenodoAccessGetAuthCode() {
window.location.href = this.configurationService.loginProviders.zenodoConfiguration.oauthUrl
+ '?client_id='
+ this.configurationService.loginProviders.zenodoConfiguration.clientId
+ '&response_type=code&scope=deposit:write+deposit:actions+user:email&state=astate&redirect_uri='
+ this.configurationService.loginProviders.zenodoConfiguration.redirectUri;
}
public zenodoLogin(code: string) {
let headers = new HttpHeaders();
headers = headers.set('Content-Type', 'application/json');
headers = headers.set('Accept', 'application/json');
this.httpClient.post(this.configurationService.server + 'auth/zenodoRequestToken', { code: code }, { headers: headers })
.pipe(takeUntil(this._destroyed))
.subscribe((responseData: any) => {
this.zenodoToken.userId = responseData.payload.userId;
this.zenodoToken.expiresIn = responseData.payload.expiresIn;
this.accessToken = this.zenodoToken.accessToken = responseData.payload.accessToken;
this.zenodoToken.email = responseData.payload.email;
this.authService.login({ ticket: this.accessToken, provider: AuthProvider.Zenodo, data: this.zenodoToken })
.pipe(takeUntil(this._destroyed))
.subscribe(
res => this.loginService.onLogInSuccess(res, this.returnUrl),
error => this.loginService.onLogInError(error)
);
});
}
public login() {
this.zenodoToken.email = this.emailFormControl.value;
this.authService.login({ ticket: this.accessToken, provider: AuthProvider.Zenodo, data: this.zenodoToken })
.pipe(takeUntil(this._destroyed))
.subscribe(
res => this.loginService.onLogInSuccess(res, this.returnUrl),
error => this.loginService.onLogInError(error)
);
}
}

View File

@ -8,7 +8,7 @@
},
"defaultCulture": "en-US",
"loginProviders": {
"enabled": [1, 2, 3, 4, 5, 6, 7, 8],
"enabled": [1, 2, 3, 4, 5, 6, 7, 8, 10],
"facebookConfiguration": { "clientId": "" },
"googleConfiguration": { "clientId": "" },
"linkedInConfiguration": {
@ -37,6 +37,11 @@
"oauthUrl": "",
"redirectUri": "",
"state": "987654321"
},
"zenodoConfiguration": {
"clientId": "",
"oauthUrl": "https://sandbox.zenodo.org/oauth/authorize",
"redirectUri": "http://localhost:4200/login/external/zenodo"
}
},
"logging": {