Add Zenodo Login and the ability to use it's access token for DOI creation
This commit is contained in:
parent
be6227a81d
commit
f39c113b7b
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}};
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<>();
|
||||
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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -7,5 +7,6 @@ export enum AuthProvider {
|
|||
B2Access = 6,
|
||||
ORCID = 7,
|
||||
OpenAire = 8,
|
||||
Configurable = 9
|
||||
Configurable = 9,
|
||||
Zenodo = 10
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 |
|
@ -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">
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
})
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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": {
|
||||
|
|
Loading…
Reference in New Issue