mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-02-01 04:09:08 +01:00
Merge branch 'develop' into bugfix/api-key-to-access-token
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
|
||||
package sonia.scm.admin;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Strings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -46,6 +47,9 @@ public class ReleaseFeedParser {
|
||||
public static final int DEFAULT_TIMEOUT_IN_MILLIS = 1000;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ReleaseFeedParser.class);
|
||||
|
||||
@VisibleForTesting
|
||||
static final String SPAN_KIND = "Release Feed";
|
||||
|
||||
private final AdvancedHttpClient client;
|
||||
private final ExecutorService executorService;
|
||||
@@ -103,7 +107,10 @@ public class ReleaseFeedParser {
|
||||
if (Strings.isNullOrEmpty(url)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
ReleaseFeedDto releaseFeed = client.get(url).request().contentFromXml(ReleaseFeedDto.class);
|
||||
ReleaseFeedDto releaseFeed = client.get(url)
|
||||
.spanKind(SPAN_KIND)
|
||||
.request()
|
||||
.contentFromXml(ReleaseFeedDto.class);
|
||||
return filterForLatestRelease(releaseFeed);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Could not parse release feed from {}", url, e);
|
||||
|
||||
@@ -30,6 +30,8 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.SCMContext;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.group.Group;
|
||||
import sonia.scm.group.GroupManager;
|
||||
import sonia.scm.plugin.Extension;
|
||||
import sonia.scm.security.AnonymousMode;
|
||||
import sonia.scm.security.PermissionAssigner;
|
||||
@@ -44,6 +46,8 @@ import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
import java.util.Collections;
|
||||
|
||||
import static sonia.scm.group.GroupCollector.AUTHENTICATED;
|
||||
|
||||
@Extension
|
||||
public class SetupContextListener implements ServletContextListener {
|
||||
|
||||
@@ -75,13 +79,18 @@ public class SetupContextListener implements ServletContextListener {
|
||||
private final PasswordService passwordService;
|
||||
private final PermissionAssigner permissionAssigner;
|
||||
private final ScmConfiguration scmConfiguration;
|
||||
private final GroupManager groupManager;
|
||||
|
||||
@VisibleForTesting
|
||||
static final String AUTHENTICATED_GROUP_DESCRIPTION = "Includes all authenticated users";
|
||||
|
||||
@Inject
|
||||
public SetupAction(UserManager userManager, PasswordService passwordService, PermissionAssigner permissionAssigner, ScmConfiguration scmConfiguration) {
|
||||
public SetupAction(UserManager userManager, PasswordService passwordService, PermissionAssigner permissionAssigner, ScmConfiguration scmConfiguration, GroupManager groupManager) {
|
||||
this.userManager = userManager;
|
||||
this.passwordService = passwordService;
|
||||
this.permissionAssigner = permissionAssigner;
|
||||
this.scmConfiguration = scmConfiguration;
|
||||
this.groupManager = groupManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,6 +101,10 @@ public class SetupContextListener implements ServletContextListener {
|
||||
if (anonymousUserRequiredButNotExists()) {
|
||||
userManager.create(SCMContext.ANONYMOUS);
|
||||
}
|
||||
|
||||
if (authenticatedGroupDoesNotExists()) {
|
||||
createAuthenticatedGroup();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean anonymousUserRequiredButNotExists() {
|
||||
@@ -115,5 +128,16 @@ public class SetupContextListener implements ServletContextListener {
|
||||
PermissionDescriptor descriptor = new PermissionDescriptor("*");
|
||||
permissionAssigner.setPermissionsForUser("scmadmin", Collections.singleton(descriptor));
|
||||
}
|
||||
|
||||
private boolean authenticatedGroupDoesNotExists() {
|
||||
return groupManager.get(AUTHENTICATED) == null;
|
||||
}
|
||||
|
||||
private void createAuthenticatedGroup() {
|
||||
Group authenticated = new Group("xml", AUTHENTICATED);
|
||||
authenticated.setDescription(AUTHENTICATED_GROUP_DESCRIPTION);
|
||||
authenticated.setExternal(true);
|
||||
groupManager.create(authenticated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.net.ahc;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
@@ -38,8 +38,11 @@ import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.net.Proxies;
|
||||
import sonia.scm.net.TrustAllHostnameVerifier;
|
||||
import sonia.scm.net.TrustAllTrustManager;
|
||||
import sonia.scm.trace.Span;
|
||||
import sonia.scm.trace.Tracer;
|
||||
import sonia.scm.util.HttpUtil;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.inject.Provider;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
@@ -99,9 +102,10 @@ public class DefaultAdvancedHttpClient extends AdvancedHttpClient
|
||||
*/
|
||||
@Inject
|
||||
public DefaultAdvancedHttpClient(ScmConfiguration configuration,
|
||||
Set<ContentTransformer> contentTransformers, Provider<SSLContext> sslContextProvider)
|
||||
Tracer tracer, Set<ContentTransformer> contentTransformers, Provider<SSLContext> sslContextProvider)
|
||||
{
|
||||
this.configuration = configuration;
|
||||
this.tracer = tracer;
|
||||
this.contentTransformers = contentTransformers;
|
||||
this.sslContextProvider = sslContextProvider;
|
||||
}
|
||||
@@ -185,45 +189,65 @@ public class DefaultAdvancedHttpClient extends AdvancedHttpClient
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
protected AdvancedHttpResponse request(BaseHttpRequest<?> request)
|
||||
throws IOException
|
||||
{
|
||||
HttpURLConnection connection = openConnection(request,
|
||||
new URL(request.getUrl()));
|
||||
protected AdvancedHttpResponse request(BaseHttpRequest<?> request) throws IOException {
|
||||
String spanKind = request.getSpanKind();
|
||||
if (Strings.isNullOrEmpty(spanKind)) {
|
||||
logger.debug("execute request {} without tracing", request.getUrl());
|
||||
return doRequest(request);
|
||||
}
|
||||
return doRequestWithTracing(request);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private DefaultAdvancedHttpResponse doRequestWithTracing(BaseHttpRequest<?> request) throws IOException {
|
||||
try (Span span = tracer.span(request.getSpanKind())) {
|
||||
span.label("url", request.getUrl());
|
||||
span.label("method", request.getMethod());
|
||||
try {
|
||||
DefaultAdvancedHttpResponse response = doRequest(request);
|
||||
span.label("status", response.getStatus());
|
||||
if (!response.isSuccessful()) {
|
||||
span.failed();
|
||||
}
|
||||
return response;
|
||||
} catch (IOException ex) {
|
||||
span.label("exception", ex.getClass().getName());
|
||||
span.label("message", ex.getMessage());
|
||||
span.failed();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private DefaultAdvancedHttpResponse doRequest(BaseHttpRequest<?> request) throws IOException {
|
||||
HttpURLConnection connection = openConnection(request, new URL(request.getUrl()));
|
||||
|
||||
applyBaseSettings(request, connection);
|
||||
|
||||
if (connection instanceof HttpsURLConnection)
|
||||
{
|
||||
if (connection instanceof HttpsURLConnection) {
|
||||
applySSLSettings(request, (HttpsURLConnection) connection);
|
||||
}
|
||||
|
||||
Content content = null;
|
||||
|
||||
if (request instanceof AdvancedHttpRequestWithBody)
|
||||
{
|
||||
if (request instanceof AdvancedHttpRequestWithBody) {
|
||||
AdvancedHttpRequestWithBody ahrwb = (AdvancedHttpRequestWithBody) request;
|
||||
|
||||
content = ahrwb.getContent();
|
||||
|
||||
if (content != null)
|
||||
{
|
||||
if (content != null) {
|
||||
content.prepare(ahrwb);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
request.header(HttpUtil.HEADER_CONTENT_LENGTH, "0");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
request.header(HttpUtil.HEADER_CONTENT_LENGTH, "0");
|
||||
}
|
||||
|
||||
applyHeaders(request, connection);
|
||||
|
||||
if (content != null)
|
||||
{
|
||||
if (content != null) {
|
||||
applyContent(connection, content);
|
||||
}
|
||||
|
||||
@@ -300,7 +324,7 @@ public class DefaultAdvancedHttpClient extends AdvancedHttpClient
|
||||
{
|
||||
TrustManager[] trustAllCerts = new TrustManager[] {
|
||||
new TrustAllTrustManager() };
|
||||
SSLContext sc = SSLContext.getInstance("SSL");
|
||||
SSLContext sc = SSLContext.getInstance("TLS");
|
||||
|
||||
sc.init(null, trustAllCerts, new java.security.SecureRandom());
|
||||
connection.setSSLSocketFactory(sc.getSocketFactory());
|
||||
@@ -309,10 +333,10 @@ public class DefaultAdvancedHttpClient extends AdvancedHttpClient
|
||||
{
|
||||
logger.error("could not disable certificate validation", ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.trace("set ssl socker factory from provider");
|
||||
logger.trace("set ssl socket factory from provider");
|
||||
connection.setSSLSocketFactory(sslContextProvider.get().getSocketFactory());
|
||||
}
|
||||
|
||||
@@ -330,7 +354,7 @@ public class DefaultAdvancedHttpClient extends AdvancedHttpClient
|
||||
|
||||
if (isProxyEnabled(request))
|
||||
{
|
||||
connection = openProxyConnection(request, url);
|
||||
connection = openProxyConnection(url);
|
||||
appendProxyAuthentication(connection);
|
||||
}
|
||||
else
|
||||
@@ -340,7 +364,9 @@ public class DefaultAdvancedHttpClient extends AdvancedHttpClient
|
||||
logger.trace("ignore proxy settings");
|
||||
}
|
||||
|
||||
logger.debug("fetch {}", url.toExternalForm());
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("fetch {}", url.toExternalForm());
|
||||
}
|
||||
|
||||
connection = createConnection(url);
|
||||
}
|
||||
@@ -348,8 +374,7 @@ public class DefaultAdvancedHttpClient extends AdvancedHttpClient
|
||||
return connection;
|
||||
}
|
||||
|
||||
private HttpURLConnection openProxyConnection(BaseHttpRequest<?> request,
|
||||
URL url)
|
||||
private HttpURLConnection openProxyConnection(URL url)
|
||||
throws IOException
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
@@ -380,7 +405,10 @@ public class DefaultAdvancedHttpClient extends AdvancedHttpClient
|
||||
|
||||
/** set of content transformers */
|
||||
private final Set<ContentTransformer> contentTransformers;
|
||||
|
||||
|
||||
/** ssl context provider */
|
||||
private final Provider<SSLContext> sslContextProvider;
|
||||
|
||||
/** tracer used for request tracing */
|
||||
private final Tracer tracer;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.plugin;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
@@ -34,6 +34,8 @@ import javax.inject.Inject;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import static sonia.scm.plugin.Tracing.SPAN_KIND;
|
||||
|
||||
class PluginCenterLoader {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(PluginCenterLoader.class);
|
||||
@@ -57,7 +59,8 @@ class PluginCenterLoader {
|
||||
Set<AvailablePlugin> load(String url) {
|
||||
try {
|
||||
LOG.info("fetch plugins from {}", url);
|
||||
PluginCenterDto pluginCenterDto = client.get(url).request().contentFromJson(PluginCenterDto.class);
|
||||
PluginCenterDto pluginCenterDto = client.get(url).spanKind(SPAN_KIND).request()
|
||||
.contentFromJson(PluginCenterDto.class);
|
||||
return mapper.map(pluginCenterDto);
|
||||
} catch (Exception ex) {
|
||||
LOG.error("failed to load plugins from plugin center, returning empty list", ex);
|
||||
|
||||
@@ -38,6 +38,8 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Optional;
|
||||
|
||||
import static sonia.scm.plugin.Tracing.SPAN_KIND;
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
// guava hash is marked as unstable
|
||||
class PluginInstaller {
|
||||
@@ -126,7 +128,7 @@ class PluginInstaller {
|
||||
}
|
||||
|
||||
private InputStream download(AvailablePlugin plugin) throws IOException {
|
||||
return client.get(plugin.getDescriptor().getUrl()).request().contentAsStream();
|
||||
return client.get(plugin.getDescriptor().getUrl()).spanKind(SPAN_KIND).request().contentAsStream();
|
||||
}
|
||||
|
||||
private Path createFile(AvailablePlugin plugin) throws IOException {
|
||||
|
||||
33
scm-webapp/src/main/java/sonia/scm/plugin/Tracing.java
Normal file
33
scm-webapp/src/main/java/sonia/scm/plugin/Tracing.java
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.plugin;
|
||||
|
||||
final class Tracing {
|
||||
|
||||
public static final String SPAN_KIND = "Plugin Center";
|
||||
|
||||
private Tracing() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.trace;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.plugin.Extension;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* An {@link Exporter} which logs every collected span.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
@Extension
|
||||
public final class LoggingExporter implements Exporter {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LoggingExporter.class);
|
||||
|
||||
private final Consumer<String> logger;
|
||||
|
||||
@Inject
|
||||
LoggingExporter() {
|
||||
this(LOG::info);
|
||||
}
|
||||
|
||||
LoggingExporter(Consumer<String> logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void export(SpanContext span) {
|
||||
logger.accept(format(span));
|
||||
}
|
||||
|
||||
private String format(SpanContext span) {
|
||||
StringBuilder message = new StringBuilder("received ");
|
||||
if (span.isFailed()) {
|
||||
message.append("failed ");
|
||||
}
|
||||
message.append(span.getKind()).append(" span, which took ");
|
||||
message.append(span.duration().toMillis()).append("ms");
|
||||
Map<String, String> labels = span.getLabels();
|
||||
if (!labels.isEmpty()) {
|
||||
message.append(":");
|
||||
for (Map.Entry<String, String> e : labels.entrySet()) {
|
||||
message.append("\n - ").append(e.getKey()).append(": ").append(e.getValue());
|
||||
}
|
||||
}
|
||||
return message.toString();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user