fixed missing ping indicator and try to create initial access token for SEB Client Config
This commit is contained in:
parent
66b77f5737
commit
a37ab31ff1
9 changed files with 425 additions and 377 deletions
|
@ -460,7 +460,7 @@ public final class ClientConnectionTable {
|
|||
}
|
||||
|
||||
void updateData(final TableItem tableItem) {
|
||||
tableItem.setText(0, getConnectionIdentifer());
|
||||
tableItem.setText(0, getConnectionIdentifier());
|
||||
tableItem.setText(1, getConnectionAddress());
|
||||
tableItem.setText(2, getStatusName());
|
||||
}
|
||||
|
@ -533,7 +533,7 @@ public final class ClientConnectionTable {
|
|||
public int compareTo(final UpdatableTableItem other) {
|
||||
return Comparator.comparingInt(UpdatableTableItem::statusWeight)
|
||||
.thenComparingInt(UpdatableTableItem::thresholdsWeight)
|
||||
.thenComparing(UpdatableTableItem::getConnectionIdentifer)
|
||||
.thenComparing(UpdatableTableItem::getConnectionIdentifier)
|
||||
.compare(this, other);
|
||||
}
|
||||
|
||||
|
@ -580,7 +580,7 @@ public final class ClientConnectionTable {
|
|||
return Constants.EMPTY_NOTE;
|
||||
}
|
||||
|
||||
String getConnectionIdentifer() {
|
||||
String getConnectionIdentifier() {
|
||||
if (this.connectionData != null && this.connectionData.clientConnection.userSessionId != null) {
|
||||
return this.connectionData.clientConnection.userSessionId;
|
||||
}
|
||||
|
@ -608,10 +608,7 @@ public final class ClientConnectionTable {
|
|||
final IndicatorData indicatorData =
|
||||
ClientConnectionTable.this.indicatorMapping.get(indicatorValue.getType());
|
||||
|
||||
if (indicatorData == null) {
|
||||
log.error("No IndicatorData of type: {} found", indicatorValue.getType());
|
||||
} else {
|
||||
|
||||
if (indicatorData != null) {
|
||||
final double value = indicatorValue.getValue();
|
||||
final int indicatorWeight = IndicatorData.getWeight(indicatorData, value);
|
||||
if (this.indicatorWeights[indicatorData.index] != indicatorWeight) {
|
||||
|
|
|
@ -57,13 +57,6 @@ public class WebserviceInit implements ApplicationListener<ApplicationReadyEvent
|
|||
|
||||
SEBServerInit.INIT_LOGGER.info("----> **** Webservice starting up... ****");
|
||||
|
||||
SEBServerInit.INIT_LOGGER.info("----> ");
|
||||
SEBServerInit.INIT_LOGGER.info("----> Init Database with flyway...");
|
||||
SEBServerInit.INIT_LOGGER.info("----> TODO ");
|
||||
|
||||
// TODO integration of Flyway for database initialization and migration: https://flywaydb.org
|
||||
// see also https://flywaydb.org/getstarted/firststeps/api
|
||||
|
||||
SEBServerInit.INIT_LOGGER.info("----> ");
|
||||
SEBServerInit.INIT_LOGGER.info("----> Intitialize Services...");
|
||||
SEBServerInit.INIT_LOGGER.info("----> ");
|
||||
|
|
|
@ -60,10 +60,10 @@ public interface ClientConfigService {
|
|||
unless = "#result.hasError()")
|
||||
Result<ClientDetails> getClientConfigDetails(String clientName);
|
||||
|
||||
@CacheEvict(
|
||||
cacheNames = EXAM_CLIENT_DETAILS_CACHE,
|
||||
allEntries = true)
|
||||
@EventListener(BulkActionEvent.class)
|
||||
void flushClientConfigData(BulkActionEvent event);
|
||||
|
||||
/** Internally used to check OAuth2 access for a active SebClientConfig.
|
||||
*
|
||||
* @param config the SebClientConfig to check access
|
||||
* @return true if the system was able to gain an access token for the client. False otherwise
|
||||
*/
|
||||
boolean checkAccess(SebClientConfig config);
|
||||
}
|
||||
|
|
|
@ -10,8 +10,7 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl;
|
|||
|
||||
import ch.ethz.seb.sebserver.WebSecurityConfig;
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig;
|
||||
|
@ -19,8 +18,6 @@ import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
|||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
import ch.ethz.seb.sebserver.webservice.WebserviceInfo;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkAction;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkActionEvent;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentialService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentials;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.InstitutionDAO;
|
||||
|
@ -38,12 +35,21 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.provider.ClientDetails;
|
||||
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
|
||||
import org.springframework.security.oauth2.provider.token.TokenStore;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -51,6 +57,7 @@ import java.io.OutputStream;
|
|||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
|
@ -316,19 +323,48 @@ public class ClientConfigServiceImpl implements ClientConfigService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void flushClientConfigData(final BulkActionEvent event) {
|
||||
try {
|
||||
final BulkAction bulkAction = event.getBulkAction();
|
||||
|
||||
if (bulkAction.type == BulkActionType.DEACTIVATE ||
|
||||
bulkAction.type == BulkActionType.HARD_DELETE) {
|
||||
|
||||
bulkAction.extractKeys(EntityType.SEB_CLIENT_CONFIGURATION)
|
||||
.forEach(this::flushClientConfigData);
|
||||
public boolean checkAccess(SebClientConfig config) {
|
||||
if(!config.isActive()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} catch (final Exception e) {
|
||||
log.error("Unexpected error while trying to flush ClientConfig data ", e);
|
||||
try {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
String externalServerURL = webserviceInfo.getExternalServerURL() +
|
||||
API.OAUTH_TOKEN_ENDPOINT;
|
||||
|
||||
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
|
||||
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
|
||||
ClientCredentials credentials = sebClientConfigDAO
|
||||
.getSebClientCredentials(config.getModelId())
|
||||
.getOrThrow();
|
||||
CharSequence plainClientSecret = clientCredentialService.getPlainClientSecret(credentials);
|
||||
String basicAuth = credentials.clientId +
|
||||
String.valueOf(Constants.COLON) +
|
||||
plainClientSecret;
|
||||
String encoded = Base64.getEncoder()
|
||||
.encodeToString(basicAuth.getBytes());
|
||||
|
||||
headers.add(HttpHeaders.AUTHORIZATION, "Basic " + encoded);
|
||||
HttpEntity<String> entity = new HttpEntity<>(
|
||||
"grant_type=client_credentials&scope=read write",
|
||||
headers);
|
||||
|
||||
ResponseEntity<String> exchange = restTemplate.exchange(
|
||||
externalServerURL,
|
||||
HttpMethod.POST,
|
||||
entity,
|
||||
String.class);
|
||||
|
||||
if (exchange.getStatusCode().value() == HttpStatus.OK.value()) {
|
||||
return true;
|
||||
} else {
|
||||
log.warn("Failed to check access SebClientConfig {} response: {}", config, exchange.getStatusCode());
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to check access for SebClientConfig: {} cause: {}", config, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
@ -93,6 +94,17 @@ public class ClientIndicatorFactory {
|
|||
final PingIntervalClientIndicator pingIndicator = this.applicationContext
|
||||
.getBean(PingIntervalClientIndicator.class);
|
||||
pingIndicator.hidden = true;
|
||||
final Indicator indicator = new Indicator(
|
||||
null,
|
||||
clientConnection.examId,
|
||||
"hidden_ping_indicator",
|
||||
IndicatorType.LAST_PING,
|
||||
"",
|
||||
Arrays.asList(new Indicator.Threshold(5000d, "")));
|
||||
pingIndicator.init(
|
||||
indicator,
|
||||
clientConnection.id,
|
||||
this.enableCaching);
|
||||
result.add(pingIndicator);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@ public final class PingIntervalClientIndicator extends AbstractPingIndicator {
|
|||
|
||||
long pingErrorThreshold;
|
||||
boolean missingPing = false;
|
||||
|
||||
boolean hidden = false;
|
||||
|
||||
public PingIntervalClientIndicator(final ClientEventExtensionMapper clientEventExtensionMapper) {
|
||||
|
|
|
@ -39,6 +39,7 @@ import org.springframework.web.bind.annotation.PathVariable;
|
|||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
@ -144,6 +145,15 @@ public class SebClientConfigController extends ActivatableEntityController<SebCl
|
|||
.map(this::checkPasswordMatch);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<SebClientConfig> notifySaved(SebClientConfig entity) {
|
||||
if (entity.isActive()) {
|
||||
// try to get access token for SEB client
|
||||
sebClientConfigService.checkAccess(entity);
|
||||
}
|
||||
return super.notifySaved(entity);
|
||||
}
|
||||
|
||||
private SebClientConfig checkPasswordMatch(final SebClientConfig entity) {
|
||||
Collection<APIMessage> errors = new ArrayList<>();
|
||||
if (entity.hasEncryptionSecret() && !entity.encryptSecret.equals(entity.encryptSecretConfirm)) {
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
|||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
|
||||
|
||||
// TODO check if we can apply some caching here to get better performance for SEB client connection attempts
|
||||
public class DefaultTokenServicesFallback extends DefaultTokenServices {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DefaultTokenServicesFallback.class);
|
||||
|
@ -29,22 +30,22 @@ public class DefaultTokenServicesFallback extends DefaultTokenServices {
|
|||
return super.createAccessToken(authentication);
|
||||
} catch (final DuplicateKeyException e) {
|
||||
|
||||
log.info(
|
||||
"Catched DuplicateKeyException, try to handle it by trying to get the already stored access token after waited some time");
|
||||
log.warn(
|
||||
"Caught DuplicateKeyException, try to handle it by trying to get the already stored access token after waited some time");
|
||||
|
||||
final String clientName = authentication.getName();
|
||||
if (StringUtils.isNotBlank(clientName)) {
|
||||
|
||||
// wait a second...
|
||||
// wait some time...
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
Thread.sleep(500);
|
||||
} catch (final InterruptedException e1) {
|
||||
log.warn("Failed to sleep: {}", e1.getMessage());
|
||||
}
|
||||
|
||||
final OAuth2AccessToken accessToken = this.getAccessToken(authentication);
|
||||
if (accessToken != null) {
|
||||
log.info("Found original accees token for client: {} token: {}", clientName, accessToken);
|
||||
log.debug("Found original access token for client: {} ", clientName);
|
||||
return accessToken;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ sebserver.init.adminaccount.gen-on-init=false
|
|||
sebserver.webservice.distributed=false
|
||||
sebserver.webservice.http.scheme=http
|
||||
sebserver.webservice.http.external.servername=
|
||||
sebserver.webservice.http.external.port=
|
||||
sebserver.webservice.http.external.port=${server.port}
|
||||
sebserver.webservice.http.redirect.gui=/gui
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue