DATABASE_NAMES = ImmutableSet.of(
- ACCESSLOG, CONFIG, COMPONENT, SECURITY);
+ CONFIG, COMPONENT, SECURITY);
private DatabaseInstanceNames() {
// no construction
diff --git a/components/nexus-orient/src/main/java/org/sonatype/nexus/orient/restore/RestoreFile.java b/components/nexus-orient/src/main/java/org/sonatype/nexus/orient/restore/RestoreFile.java
index fdb64ff2f5..ca682edabb 100644
--- a/components/nexus-orient/src/main/java/org/sonatype/nexus/orient/restore/RestoreFile.java
+++ b/components/nexus-orient/src/main/java/org/sonatype/nexus/orient/restore/RestoreFile.java
@@ -32,8 +32,8 @@
*
* Examples:
*
- * accesslog-2017-07-06-11-16-49-3.4.1.bak
- * accesslog-2017-07-06-11-16-49.bak
+ * component-2017-07-06-11-16-49-3.4.1.bak
+ * component-2017-07-06-11-16-49.bak
*
*
* The nxrm_version will not be present for files generated pre-3.4.1.
diff --git a/components/nexus-orient/src/test/java/org/sonatype/nexus/orient/restore/RestoreServiceImplTest.groovy b/components/nexus-orient/src/test/java/org/sonatype/nexus/orient/restore/RestoreServiceImplTest.groovy
index 4b7850bc67..66079fdf0b 100644
--- a/components/nexus-orient/src/test/java/org/sonatype/nexus/orient/restore/RestoreServiceImplTest.groovy
+++ b/components/nexus-orient/src/test/java/org/sonatype/nexus/orient/restore/RestoreServiceImplTest.groovy
@@ -67,7 +67,6 @@ class RestoreServiceImplTest
restorer.getPendingRestore(names.next()) >> mockRestoreFile(_, '2017-07-06-11-16-49', null)
restorer.getPendingRestore(names.next()) >> mockRestoreFile(_, '2017-07-06-11-16-50', null)
restorer.getPendingRestore(names.next()) >> mockRestoreFile(_, '2017-07-06-11-16-51', null)
- restorer.getPendingRestore(names.next()) >> mockRestoreFile(_, '2017-07-06-11-16-52', null)
when: 'start is executed'
restoreService.start()
diff --git a/components/nexus-rapture/src/main/resources/static/rapture/NX/view/SignIn.js b/components/nexus-rapture/src/main/resources/static/rapture/NX/view/SignIn.js
index 776536b4cb..e823fd3abd 100644
--- a/components/nexus-rapture/src/main/resources/static/rapture/NX/view/SignIn.js
+++ b/components/nexus-rapture/src/main/resources/static/rapture/NX/view/SignIn.js
@@ -78,6 +78,32 @@ Ext.define('NX.view.SignIn', {
});
me.callParent();
+ },
+
+ addMessage: function(message) {
+ var me = this,
+ htmlMessage = '' + message + '
',
+ messageCmp = me.down('#signinMessage');
+
+ if (messageCmp) {
+ messageCmp.html(htmlMessage);
+ }
+ else {
+ me.down('form').insert(0, {
+ xtype: 'component',
+ itemId: 'signinMessage',
+ html: htmlMessage
+ });
+ }
+ },
+
+ clearMessage: function() {
+ var me = this,
+ messageCmp = me.down('#signinMessage');
+
+ if (messageCmp) {
+ me.down('form').remove(messageCmp);
+ }
}
});
diff --git a/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/ETagHeaderUtils.java b/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/ETagHeaderUtils.java
new file mode 100644
index 0000000000..2cbdcf5eac
--- /dev/null
+++ b/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/ETagHeaderUtils.java
@@ -0,0 +1,46 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2008-present Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+package org.sonatype.nexus.repository;
+
+import static org.apache.commons.lang.StringUtils.isEmpty;
+
+public class ETagHeaderUtils
+{
+ public static final String WEAK_DESIGNATOR = "W/";
+
+ private ETagHeaderUtils() {
+ }
+
+ /**
+ * Adds quotes to etag header per spec.
+ * https://tools.ietf.org/html/rfc7232#section-2.3
+ */
+ public static String quote(final String etag) {
+ if (etag.startsWith(WEAK_DESIGNATOR)) {
+ return etag;
+ } else {
+ return "\"" + etag + "\"";
+ }
+ }
+
+ /**
+ * Removes quotes from etag header.
+ */
+ public static String extract(final String etag) {
+ if (!isEmpty(etag) && etag.startsWith("\"") && etag.endsWith("\"")) {
+ return etag.substring(1, etag.length() - 1);
+ } else {
+ return etag;
+ }
+ }
+}
diff --git a/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/proxy/ProxyFacetSupport.java b/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/proxy/ProxyFacetSupport.java
index 66d13b7d50..a222728409 100644
--- a/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/proxy/ProxyFacetSupport.java
+++ b/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/proxy/ProxyFacetSupport.java
@@ -27,6 +27,7 @@
import org.sonatype.nexus.common.io.Cooperation;
import org.sonatype.nexus.common.io.CooperationFactory;
import org.sonatype.nexus.repository.BadRequestException;
+import org.sonatype.nexus.repository.ETagHeaderUtils;
import org.sonatype.nexus.repository.FacetSupport;
import org.sonatype.nexus.repository.InvalidContentException;
import org.sonatype.nexus.repository.cache.CacheController;
@@ -45,7 +46,6 @@
import org.sonatype.nexus.validation.constraint.Url;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Strings;
import com.google.common.io.Closeables;
import com.google.common.net.HttpHeaders;
import org.apache.http.Header;
@@ -73,6 +73,7 @@ public abstract class ProxyFacetSupport
extends FacetSupport
implements ProxyFacet
{
+
@VisibleForTesting
static final String CONFIG_KEY = "proxy";
@@ -416,7 +417,7 @@ protected Content fetch(String url, Context context, @Nullable Content stale) th
}
final String etag = stale.getAttributes().get(Content.CONTENT_ETAG, String.class);
if (etag != null) {
- request.addHeader(HttpHeaders.IF_NONE_MATCH, "\"" + etag + "\"");
+ request.addHeader(HttpHeaders.IF_NONE_MATCH, ETagHeaderUtils.quote(etag));
}
}
log.debug("Fetching: {}", request);
@@ -435,7 +436,9 @@ protected Content fetch(String url, Context context, @Nullable Content stale) th
final Content result = createContent(context, response);
result.getAttributes().set(Content.CONTENT_LAST_MODIFIED, extractLastModified(request, response));
- result.getAttributes().set(Content.CONTENT_ETAG, extractETag(response));
+ final Header etagHeader = response.getLastHeader(HttpHeaders.ETAG);
+ result.getAttributes().set(Content.CONTENT_ETAG, etagHeader == null ? null : ETagHeaderUtils.extract(etagHeader.getValue()));
+
result.getAttributes().set(CacheInfo.class, cacheInfo);
return result;
}
@@ -509,26 +512,6 @@ private DateTime extractLastModified(final HttpRequestBase request, final HttpRe
return null;
}
- /**
- * Extract ETag from response if possible, or {@code null}.
- */
- @Nullable
- private String extractETag(final HttpResponse response) {
- final Header etagHeader = response.getLastHeader(HttpHeaders.ETAG);
- if (etagHeader != null) {
- final String etag = etagHeader.getValue();
- if (!Strings.isNullOrEmpty(etag)) {
- if (etag.startsWith("\"") && etag.endsWith("\"")) {
- return etag.substring(1, etag.length() - 1);
- }
- else {
- return etag;
- }
- }
- }
- return null;
- }
-
/**
* For whatever component/asset
*/
diff --git a/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/view/handlers/ContentHeadersHandler.java b/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/view/handlers/ContentHeadersHandler.java
index f7199b434d..c02639dd78 100644
--- a/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/view/handlers/ContentHeadersHandler.java
+++ b/components/nexus-repository/src/main/java/org/sonatype/nexus/repository/view/handlers/ContentHeadersHandler.java
@@ -17,6 +17,7 @@
import javax.inject.Singleton;
import org.sonatype.goodies.common.ComponentSupport;
+import org.sonatype.nexus.repository.ETagHeaderUtils;
import org.sonatype.nexus.repository.view.Content;
import org.sonatype.nexus.repository.view.Context;
import org.sonatype.nexus.repository.view.Handler;
@@ -53,7 +54,7 @@ public Response handle(@Nonnull final Context context) throws Exception {
}
final String etag = content.getAttributes().get(Content.CONTENT_ETAG, String.class);
if (etag != null) {
- response.getHeaders().set(HttpHeaders.ETAG, "\"" + etag + "\"");
+ response.getHeaders().set(HttpHeaders.ETAG, ETagHeaderUtils.quote(etag));
}
}
return response;
diff --git a/components/nexus-repository/src/test/java/org/sonatype/nexus/repository/ETagHeaderUtilsTest.java b/components/nexus-repository/src/test/java/org/sonatype/nexus/repository/ETagHeaderUtilsTest.java
new file mode 100644
index 0000000000..2ae6e17639
--- /dev/null
+++ b/components/nexus-repository/src/test/java/org/sonatype/nexus/repository/ETagHeaderUtilsTest.java
@@ -0,0 +1,51 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2008-present Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+package org.sonatype.nexus.repository;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+public class ETagHeaderUtilsTest
+{
+ @Test
+ public void quoteStrong() {
+ assertEquals("\"foobar\"", ETagHeaderUtils.quote("foobar"));
+ }
+
+ @Test
+ public void quoteWeak() {
+ assertEquals("W/\"foobar\"", ETagHeaderUtils.quote("W/\"foobar\""));
+ }
+
+ @Test
+ public void extractNull() {
+ assertNull(ETagHeaderUtils.extract(null));
+ }
+
+ @Test
+ public void extractEmpty() {
+ assertEquals("", ETagHeaderUtils.extract(""));
+ }
+
+ @Test
+ public void extractStrong() {
+ assertEquals("foobar", ETagHeaderUtils.extract("\"foobar\""));
+ }
+
+ @Test
+ public void extractWeak() {
+ assertEquals("W/\"foobar\"", ETagHeaderUtils.extract("W/\"foobar\""));
+ }
+}
diff --git a/components/nexus-repository/src/test/java/org/sonatype/nexus/repository/view/handlers/ContentHeadersHandlerTest.java b/components/nexus-repository/src/test/java/org/sonatype/nexus/repository/view/handlers/ContentHeadersHandlerTest.java
index f42d045483..a9a2b30f48 100644
--- a/components/nexus-repository/src/test/java/org/sonatype/nexus/repository/view/handlers/ContentHeadersHandlerTest.java
+++ b/components/nexus-repository/src/test/java/org/sonatype/nexus/repository/view/handlers/ContentHeadersHandlerTest.java
@@ -70,6 +70,18 @@ public void okResponse() throws Exception {
assertThat(r.getHeaders().get(HttpHeaders.ETAG), equalTo("\"etag\""));
}
+ @Test
+ public void okResponseWithWeakEtag() throws Exception {
+ final Content content = new Content(new StringPayload(payloadString, "text/plain"));
+ content.getAttributes().set(Content.CONTENT_LAST_MODIFIED, now);
+ content.getAttributes().set(Content.CONTENT_ETAG, "W/\"etag\"");
+ when(context.proceed()).thenReturn(HttpResponses.ok(content));
+ final Response r = subject.handle(context);
+ assertThat(r.getStatus().isSuccessful(), is(true));
+ assertThat(r.getHeaders().get(HttpHeaders.LAST_MODIFIED), equalTo(DateTimeUtils.formatDateTime(now)));
+ assertThat(r.getHeaders().get(HttpHeaders.ETAG), equalTo("W/\"etag\""));
+ }
+
@Test
public void okResponseNoExtraData() throws Exception {
when(context.proceed()).thenReturn(
diff --git a/components/nexus-security/src/main/java/org/sonatype/nexus/security/config/AdminPasswordFileManager.java b/components/nexus-security/src/main/java/org/sonatype/nexus/security/config/AdminPasswordFileManager.java
index cc8c9bf946..1041fc3770 100644
--- a/components/nexus-security/src/main/java/org/sonatype/nexus/security/config/AdminPasswordFileManager.java
+++ b/components/nexus-security/src/main/java/org/sonatype/nexus/security/config/AdminPasswordFileManager.java
@@ -21,6 +21,8 @@ public interface AdminPasswordFileManager
{
boolean exists();
+ String getPath();
+
boolean writeFile(String password) throws IOException;
String readFile() throws IOException;
diff --git a/components/nexus-security/src/main/java/org/sonatype/nexus/security/internal/AdminPasswordFileManagerImpl.java b/components/nexus-security/src/main/java/org/sonatype/nexus/security/internal/AdminPasswordFileManagerImpl.java
index 5a1455c863..294cffd9a0 100644
--- a/components/nexus-security/src/main/java/org/sonatype/nexus/security/internal/AdminPasswordFileManagerImpl.java
+++ b/components/nexus-security/src/main/java/org/sonatype/nexus/security/internal/AdminPasswordFileManagerImpl.java
@@ -77,6 +77,11 @@ public boolean exists() {
return adminPasswordFile.exists();
}
+ @Override
+ public String getPath() {
+ return adminPasswordFile.getAbsolutePath();
+ }
+
@Override
public String readFile() throws IOException {
if (adminPasswordFile.exists()) {
diff --git a/components/nexus-security/src/test/java/org/sonatype/nexus/security/internal/AdminPasswordFileManagerImplTest.java b/components/nexus-security/src/test/java/org/sonatype/nexus/security/internal/AdminPasswordFileManagerImplTest.java
index 457524a4d8..d8cb12ca6d 100644
--- a/components/nexus-security/src/test/java/org/sonatype/nexus/security/internal/AdminPasswordFileManagerImplTest.java
+++ b/components/nexus-security/src/test/java/org/sonatype/nexus/security/internal/AdminPasswordFileManagerImplTest.java
@@ -55,6 +55,12 @@ public void testExists() throws Exception {
assertThat(underTest.exists(), is(false));
}
+ @Test
+ public void testGetPath() {
+ File passwordFile = new File(applicationDirectories.getWorkDirectory(), "admin.password");
+ assertThat(passwordFile.getAbsolutePath(), is(underTest.getPath()));
+ }
+
@Test
public void testWriteFile() throws Exception {
underTest.writeFile("testpass");
diff --git a/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/app/PluginConfig.js b/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/app/PluginConfig.js
index 7182536711..b38d731945 100644
--- a/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/app/PluginConfig.js
+++ b/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/app/PluginConfig.js
@@ -175,12 +175,8 @@ Ext.define('NX.coreui.app.PluginConfig', {
return NX.app.Application.bundleActive('org.sonatype.nexus.plugins.nexus-coreui-plugin');
}
},
- { id: 'NX.coreui.controller.Licensing',
- active: function () {
- return NX.app.Application.bundleActive('com.sonatype.nexus.plugins.nexus-licensing-plugin');
- }
- },
- { id: 'NX.coreui.controller.LicenseUsers',
+ {
+ id: 'NX.coreui.controller.Licensing',
active: function () {
return NX.app.Application.bundleActive('com.sonatype.nexus.plugins.nexus-licensing-plugin');
}
diff --git a/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/app/PluginStrings.js b/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/app/PluginStrings.js
index bbe4aa15cd..8411c5b43f 100644
--- a/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/app/PluginStrings.js
+++ b/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/app/PluginStrings.js
@@ -1310,7 +1310,6 @@ Ext.define('NX.coreui.app.PluginStrings', {
Licensing_LicensingDetails_ExpirationDate_FieldLabel: 'Expiration date',
Licensing_LicensingDetails_Type_FieldLabel: 'License type',
Licensing_LicensingDetails_LicensedUsers_FieldLabel: 'Number of licensed users',
- Licensing_LicensingDetails_Connections_FieldLabel: 'Number of unique IP addresses that have connected in the last 7 days',
Licensing_LicensingDetails_Fingerprint_FieldLabel: 'Fingerprint',
Licensing_LicensingDetails_InstallLicense_Title: 'Install license',
Licensing_LicensingDetails_InstallLicense_Html: 'Installing a new license requires restarting the server to take effect
',
@@ -1323,16 +1322,6 @@ Ext.define('NX.coreui.app.PluginStrings', {
Licensing_Install_Success: 'License installed. Restart is only required if you are enabling new PRO features.',
Licensing_Authentication_Validation: '{0} a license requires validation of your credentials.',
- // Admin -> System -> Licensing -> Recent Connections
- LicenseUsers_Title: 'Recent Connections',
- LicenseUsers_Description: 'Reports active users in the last 7 days',
- Licensing_LicenseUserList_Download_Button: 'Download',
- Licensing_LicenseUserList_IP_Header: 'IP',
- Licensing_LicenseUserList_Date_Header: 'Date',
- Licensing_LicenseUserList_User_Header: 'User',
- Licensing_LicenseUserList_Agent_Header: 'User agent',
- Licensing_LicenseUserList_EmptyText: 'No active users in the last 7 days.',
-
//Nexus Lifecycle -> Server
Clm_ClmSettings_Permission_Error: 'You do not have permission to configure IQ Server',
Clm_Text: 'IQ Server',
diff --git a/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/controller/LicenseUsers.js b/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/controller/LicenseUsers.js
deleted file mode 100644
index 3098d6797a..0000000000
--- a/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/controller/LicenseUsers.js
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Sonatype Nexus (TM) Open Source Version
- * Copyright (c) 2008-present Sonatype, Inc.
- * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
- *
- * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
- * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
- * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
- * Eclipse Foundation. All other trademarks are the property of their respective owners.
- */
-/*global Ext, NX*/
-
-/**
- * License Users controller.
- *
- * @since 3.0
- */
-Ext.define('NX.coreui.controller.LicenseUsers', {
- extend: 'NX.app.Controller',
- requires: [
- 'NX.Permissions',
- 'NX.util.DownloadHelper',
- 'NX.util.Url',
- 'NX.I18n'
- ],
-
- stores: [
- 'LicenseUser'
- ],
- views: [
- 'licensing.LicenseUserList'
- ],
- refs: [
- {
- ref: 'list',
- selector: 'nx-coreui-licensing-licenseuser-list'
- }
- ],
-
- /**
- * @override
- */
- init: function () {
- var me = this;
-
- me.getApplication().getIconController().addIcons({
- 'licenseuser-default': {
- file: 'ssl_certificates.png',
- variants: ['x16', 'x32']
- }
- });
-
- me.getApplication().getFeaturesController().registerFeature({
- mode: 'admin',
- path: '/System/Licensing/License Users',
- text: NX.I18n.get('LicenseUsers_Title'),
- description: NX.I18n.get('LicenseUsers_Description'),
- view: { xtype: 'nx-coreui-licensing-licenseuser-list' },
- iconConfig: {
- file: 'ssl_tls_manager.png',
- variants: ['x16', 'x32']
- },
- visible: function () {
- return NX.Permissions.check('nexus:licensing:read');
- }
- }, me);
-
- me.listen({
- controller: {
- '#Refresh': {
- refresh: me.load
- }
- },
- component: {
- 'nx-coreui-licensing-licenseuser-list': {
- afterrender: me.load
- },
- 'nx-coreui-licensing-licenseuser-list button[action=download]': {
- click: me.download
- }
- }
- });
- },
-
- /**
- * @private
- * Load active user store.
- */
- load: function () {
- var list = this.getList();
-
- if (list) {
- list.getStore().load();
- }
- },
-
- /**
- * @private
- * Download active users in CSV format.
- */
- download: function () {
- NX.util.DownloadHelper.downloadUrl(NX.util.Url.urlOf('service/rest/licensing/csv_access_data'));
- }
-
-});
diff --git a/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/view/licensing/LicenseUserList.js b/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/view/licensing/LicenseUserList.js
deleted file mode 100644
index 32c3e98e66..0000000000
--- a/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/view/licensing/LicenseUserList.js
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Sonatype Nexus (TM) Open Source Version
- * Copyright (c) 2008-present Sonatype, Inc.
- * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
- *
- * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
- * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
- * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
- * Eclipse Foundation. All other trademarks are the property of their respective owners.
- */
-/*global Ext, NX*/
-
-/**
- * License User grid.
- *
- * @since 3.0
- */
-Ext.define('NX.coreui.view.licensing.LicenseUserList', {
- extend: 'Ext.grid.Panel',
- alias: 'widget.nx-coreui-licensing-licenseuser-list',
- requires: [
- 'NX.I18n'
- ],
-
- stateful: true,
- stateId: 'nx-coreui-licensing-licenseuser-list',
-
- /**
- * @override
- */
- initComponent: function() {
- Ext.apply(this, {
- store: 'LicenseUser',
-
- columns: [
- {
- xtype: 'nx-iconcolumn',
- width: 36,
- iconVariant: 'x16',
- iconName: function () {
- return 'licenseuser-default';
- }
- },
- { header: NX.I18n.get('Licensing_LicenseUserList_IP_Header'), dataIndex: 'ip', stateId: 'ip', flex: 1 },
- { header: NX.I18n.get('Licensing_LicenseUserList_Date_Header'), dataIndex: 'timestamp', stateId: 'timestamp', flex: 1 },
- { header: NX.I18n.get('Licensing_LicenseUserList_User_Header'), dataIndex: 'userId', stateId: 'userId', flex: 1 },
- { header: NX.I18n.get('Licensing_LicenseUserList_Agent_Header'), dataIndex: 'userAgent', stateId: 'userAgent', flex: 2 }
- ],
-
- viewConfig: {
- emptyText: NX.I18n.get('Licensing_LicenseUserList_EmptyText'),
- deferEmptyText: false
- },
-
- dockedItems: [{
- xtype: 'nx-actions',
- items: {
- xtype: 'button',
- text: NX.I18n.get('Licensing_LicenseUserList_Download_Button'),
- glyph: 'xf019@FontAwesome' /* fa-download */,
- action: 'download'
- }
- }],
-
- plugins: [{ ptype: 'gridfilterbox', emptyText: 'No license user matched criteria "$filter"' }]
- });
-
- this.callParent();
- }
-
-});
diff --git a/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/view/licensing/LicensingDetails.js b/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/view/licensing/LicensingDetails.js
index 793ff5a6a9..d2e67f83e4 100644
--- a/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/view/licensing/LicensingDetails.js
+++ b/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/view/licensing/LicensingDetails.js
@@ -88,11 +88,6 @@ Ext.define('NX.coreui.view.licensing.LicensingDetails', {
fieldLabel: NX.I18n.get('Licensing_LicensingDetails_LicensedUsers_FieldLabel'),
xtype: 'displayfield'
},
- {
- name: 'connections',
- fieldLabel: NX.I18n.get('Licensing_LicensingDetails_Connections_FieldLabel'),
- xtype: 'displayfield'
- },
{
name: 'fingerprint',
fieldLabel: NX.I18n.get('Licensing_LicensingDetails_Fingerprint_FieldLabel'),
diff --git a/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/view/repository/recipe/AptProxy.js b/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/view/repository/recipe/AptProxy.js
index 080d316582..de8f91b2bd 100644
--- a/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/view/repository/recipe/AptProxy.js
+++ b/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/view/repository/recipe/AptProxy.js
@@ -21,6 +21,7 @@ Ext.define('NX.coreui.view.repository.recipe.AptProxy', {
requires: [
'NX.coreui.view.repository.facet.AptFacet',
'NX.coreui.view.repository.facet.ProxyFacet',
+ 'NX.coreui.view.repository.facet.RoutingRuleFacet',
'NX.coreui.view.repository.facet.StorageFacet',
'NX.coreui.view.repository.facet.HttpClientFacet',
'NX.coreui.view.repository.facet.NegativeCacheFacet',
@@ -36,6 +37,7 @@ Ext.define('NX.coreui.view.repository.recipe.AptProxy', {
me.items = [
{xtype: 'nx-aptui-repository-apt-facet'},
{xtype: 'nx-coreui-repository-proxy-facet'},
+ {xtype: 'nx-coreui-repository-routing-rule-facet'},
{xtype: 'nx-coreui-repository-storage-facet'},
{xtype: 'nx-coreui-repository-negativecache-facet'},
{xtype: 'nx-coreui-repository-cleanup-policy-facet'},
diff --git a/plugins/nexus-onboarding-plugin/src/main/java/org/sonatype/nexus/onboarding/internal/OnboardingStateContributor.java b/plugins/nexus-onboarding-plugin/src/main/java/org/sonatype/nexus/onboarding/internal/OnboardingStateContributor.java
index 834210a68b..b3ffd76772 100644
--- a/plugins/nexus-onboarding-plugin/src/main/java/org/sonatype/nexus/onboarding/internal/OnboardingStateContributor.java
+++ b/plugins/nexus-onboarding-plugin/src/main/java/org/sonatype/nexus/onboarding/internal/OnboardingStateContributor.java
@@ -12,7 +12,7 @@
*/
package org.sonatype.nexus.onboarding.internal;
-import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;
@@ -23,9 +23,7 @@
import org.sonatype.nexus.onboarding.OnboardingConfiguration;
import org.sonatype.nexus.onboarding.OnboardingManager;
import org.sonatype.nexus.rapture.StateContributor;
-import org.sonatype.nexus.security.SecurityHelper;
-
-import org.apache.shiro.subject.Subject;
+import org.sonatype.nexus.security.config.AdminPasswordFileManager;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -41,18 +39,18 @@ public class OnboardingStateContributor
private final OnboardingManager onboardingManager;
- private final SecurityHelper securityHelper;
+ private final AdminPasswordFileManager adminPasswordFileManager;
private boolean needsOnboarding = true;
@Inject
public OnboardingStateContributor(final OnboardingConfiguration onboardingConfiguration,
final OnboardingManager onboardingManager,
- final SecurityHelper securityHelper)
+ final AdminPasswordFileManager adminPasswordFileManager)
{
this.onboardingConfiguration = checkNotNull(onboardingConfiguration);
this.onboardingManager = checkNotNull(onboardingManager);
- this.securityHelper = checkNotNull(securityHelper);
+ this.adminPasswordFileManager = checkNotNull(adminPasswordFileManager);
}
@Nullable
@@ -61,18 +59,16 @@ public Map getState() {
//cache the onboarding flag, once it's false there is no longer a need to check anymore
needsOnboarding = needsOnboarding && onboardingConfiguration.isEnabled() && onboardingManager.needsOnboarding();
- if (needsOnboarding && isAdmin(securityHelper.subject())) {
- return Collections.singletonMap("onboarding.required", true);
- }
+ HashMap properties = new HashMap<>();
- return null;
- }
+ if (needsOnboarding) {
+ properties.put("onboarding.required", true);
+ }
- private boolean isAdmin(Subject subject) {
- if (subject == null || subject.getPrincipal() == null) {
- return false;
+ if (adminPasswordFileManager.exists()) {
+ properties.put("admin.password.file", adminPasswordFileManager.getPath());
}
- return subject.isPermitted("nexus:*");
+ return properties.isEmpty() ? null : properties;
}
}
diff --git a/plugins/nexus-onboarding-plugin/src/main/resources/static/rapture/NX/onboarding/app/PluginStrings.js b/plugins/nexus-onboarding-plugin/src/main/resources/static/rapture/NX/onboarding/app/PluginStrings.js
index 591bc74b92..0ced730557 100644
--- a/plugins/nexus-onboarding-plugin/src/main/resources/static/rapture/NX/onboarding/app/PluginStrings.js
+++ b/plugins/nexus-onboarding-plugin/src/main/resources/static/rapture/NX/onboarding/app/PluginStrings.js
@@ -25,7 +25,8 @@ Ext.define('NX.onboarding.app.PluginStrings', {
keys: {
Onboarding_Text: 'Onboarding',
- Onboarding_Description: 'Configuration changes requiring attention'
+ Onboarding_Description: 'Configuration changes requiring attention',
+ Onboarding_Authenticate: 'Your admin user password is located in
{0} on the server.'
},
bundles: {
diff --git a/plugins/nexus-onboarding-plugin/src/main/resources/static/rapture/NX/onboarding/controller/Onboarding.js b/plugins/nexus-onboarding-plugin/src/main/resources/static/rapture/NX/onboarding/controller/Onboarding.js
index 0dc3a790f9..414cf9d105 100644
--- a/plugins/nexus-onboarding-plugin/src/main/resources/static/rapture/NX/onboarding/controller/Onboarding.js
+++ b/plugins/nexus-onboarding-plugin/src/main/resources/static/rapture/NX/onboarding/controller/Onboarding.js
@@ -50,6 +50,9 @@ Ext.define('NX.onboarding.controller.Onboarding', {
component: {
'nx-onboarding-wizard': {
closed: me.reset
+ },
+ 'nx-signin': {
+ beforeshow: me.beforeShowSignin
}
},
controller: {
@@ -65,8 +68,21 @@ Ext.define('NX.onboarding.controller.Onboarding', {
});
},
+ beforeShowSignin: function(signin) {
+ var doOnboarding = NX.State.getValue('onboarding.required'),
+ passwordFile = NX.State.getValue("admin.password.file"),
+ msg = NX.I18n.format('Onboarding_Authenticate', Ext.htmlEncode(passwordFile));
+
+ if (doOnboarding && passwordFile) {
+ signin.addMessage(msg);
+ }
+ else {
+ signin.clearMessage();
+ }
+ },
+
stateChanged: function() {
- if (NX.State.getValue('onboarding.required', false)) {
+ if (NX.State.getValue('onboarding.required') && NX.State.getUser()) {
this.loadItems();
}
},
diff --git a/plugins/nexus-onboarding-plugin/src/test/java/org/sonatype/nexus/onboarding/internal/OnboardingStateContributorTest.java b/plugins/nexus-onboarding-plugin/src/test/java/org/sonatype/nexus/onboarding/internal/OnboardingStateContributorTest.java
index 72ecd0c5f4..bd177a2209 100644
--- a/plugins/nexus-onboarding-plugin/src/test/java/org/sonatype/nexus/onboarding/internal/OnboardingStateContributorTest.java
+++ b/plugins/nexus-onboarding-plugin/src/test/java/org/sonatype/nexus/onboarding/internal/OnboardingStateContributorTest.java
@@ -19,9 +19,8 @@
import org.sonatype.nexus.onboarding.OnboardingConfiguration;
import org.sonatype.nexus.onboarding.OnboardingItem;
import org.sonatype.nexus.onboarding.OnboardingManager;
-import org.sonatype.nexus.security.SecurityHelper;
+import org.sonatype.nexus.security.config.AdminPasswordFileManager;
-import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
@@ -41,7 +40,7 @@ public class OnboardingStateContributorTest
private OnboardingManager onboardingManager;
@Mock
- private SecurityHelper securityHelper;
+ private AdminPasswordFileManager adminPasswordFileManager;
@Mock
private OnboardingItem onboardingItem1;
@@ -49,9 +48,6 @@ public class OnboardingStateContributorTest
@Mock
private OnboardingItem onboardingItem2;
- @Mock
- private Subject subject;
-
private OnboardingStateContributor underTest;
@Before
@@ -59,42 +55,26 @@ public void setup() {
when(onboardingConfiguration.isEnabled()).thenReturn(true);
when(onboardingManager.getOnboardingItems()).thenReturn(Arrays.asList(onboardingItem1, onboardingItem2));
when(onboardingManager.needsOnboarding()).thenReturn(true);
- when(securityHelper.subject()).thenReturn(subject);
- when(subject.isPermitted("nexus:*")).thenReturn(true);
- when(subject.getPrincipal()).thenReturn(new Object());
+ when(adminPasswordFileManager.exists()).thenReturn(true);
+ when(adminPasswordFileManager.getPath()).thenReturn("path/to/file");
- underTest = new OnboardingStateContributor(onboardingConfiguration, onboardingManager, securityHelper);
+ underTest = new OnboardingStateContributor(onboardingConfiguration, onboardingManager, adminPasswordFileManager);
}
@Test
public void testGetState() {
Map state = underTest.getState();
- assertThat(state.size(), is(1));
+ assertThat(state.size(), is(2));
assertThat(state.get("onboarding.required"), is(true));
+ assertThat(state.get("admin.password.file"), is("path/to/file"));
}
@Test
public void testGetState_noItems() {
when(onboardingManager.needsOnboarding()).thenReturn(false);
+ when(adminPasswordFileManager.exists()).thenReturn(false);
- Map state = underTest.getState();
- assertThat(state, nullValue());
- }
-
- @Test
- public void testGetState_noAuthz() {
- when(subject.isPermitted("nexus:*")).thenReturn(false);
-
- Map state = underTest.getState();
- assertThat(state, nullValue());
- }
-
- @Test
- public void testGetState_noPrincipal() {
- when(subject.getPrincipal()).thenReturn(null);
-
- Map state = underTest.getState();
- assertThat(state, nullValue());
+ assertThat(underTest.getState(), nullValue());
}
@Test
@@ -105,12 +85,20 @@ public void testGetState_cacheOnboardingState() {
when(onboardingManager.needsOnboarding()).thenReturn(false);
state = underTest.getState();
- assertThat(state, nullValue());
+ assertThat(state.get("onboarding.required"), nullValue());
//set to true to validate that cache kicks in and still doesn't add data to the map
when(onboardingManager.needsOnboarding()).thenReturn(true);
state = underTest.getState();
- assertThat(state, nullValue());
+ assertThat(state.get("onboarding.required"), nullValue());
+ }
+
+ @Test
+ public void testGetState_noAdminPasswordFile() {
+ when(adminPasswordFileManager.exists()).thenReturn(false);
+
+ Map state = underTest.getState();
+ assertThat(state.get("admin.password.file"), nullValue());
}
}
diff --git a/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/AptFacet.java b/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/AptFacet.java
index 018430686e..2e51ae5f31 100644
--- a/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/AptFacet.java
+++ b/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/AptFacet.java
@@ -18,6 +18,8 @@
import org.sonatype.nexus.repository.Facet;
import org.sonatype.nexus.repository.apt.internal.debian.PackageInfo;
+import org.sonatype.nexus.repository.storage.Asset;
+import org.sonatype.nexus.repository.storage.StorageTx;
import org.sonatype.nexus.repository.view.Content;
import org.sonatype.nexus.repository.view.Payload;
@@ -29,13 +31,17 @@ public interface AptFacet
extends Facet
{
@Nullable
- Content get(String path) throws IOException;
+ Content get(final String path) throws IOException;
- Content put(String path, Payload payload) throws IOException;
+ Content put(final String path, final Payload payload) throws IOException;
- Content put(String path, Payload payload, @Nullable PackageInfo packageInfo) throws IOException;
+ Content put(final String path, final Payload payload, @Nullable final PackageInfo packageInfo) throws IOException;
- boolean delete(String path) throws IOException;
+ boolean delete(final String path) throws IOException;
+
+ Asset findOrCreateDebAsset(final StorageTx tx, final String path, final PackageInfo packageInfo);
+
+ Asset findOrCreateMetadataAsset(final StorageTx tx, final String path);
boolean isFlat();
diff --git a/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/store/LicenseUser.js b/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/AptRestoreFacet.java
similarity index 53%
rename from plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/store/LicenseUser.js
rename to plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/AptRestoreFacet.java
index 1a2802b90c..730fa59070 100644
--- a/plugins/nexus-coreui-plugin/src/main/resources/static/rapture/NX/coreui/store/LicenseUser.js
+++ b/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/AptRestoreFacet.java
@@ -10,31 +10,28 @@
* of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
* Eclipse Foundation. All other trademarks are the property of their respective owners.
*/
-/*global Ext, NX*/
+package org.sonatype.nexus.repository.apt;
+
+import java.io.IOException;
+
+import org.sonatype.nexus.blobstore.api.Blob;
+import org.sonatype.nexus.repository.Facet;
+import org.sonatype.nexus.repository.Type;
+import org.sonatype.nexus.repository.storage.AssetBlob;
+import org.sonatype.nexus.repository.storage.Query;
+import org.sonatype.nexus.repository.view.Content;
/**
- * License User store.
- *
- * @since 3.0
+ * @since 3.next
*/
-Ext.define('NX.coreui.store.LicenseUser', {
- extend: 'Ext.data.Store',
- model: 'NX.coreui.model.LicenseUser',
-
- proxy: {
- type: 'direct',
- paramsAsHash: false,
+@Facet.Exposed
+public interface AptRestoreFacet extends Facet
+{
+ Content restore(final AssetBlob assetBlob, final String path) throws IOException;
- api: {
- read: 'NX.direct.licensing_Licensing.readLicenseUsers'
- },
+ boolean assetExists(final String path);
- reader: {
- type: 'json',
- rootProperty: 'data',
- successProperty: 'success'
- }
- },
+ Query getComponentQuery(final Blob blob) throws IOException;
- sorters: { property: 'timestamp', direction: 'DESC' }
-});
+ boolean componentRequired(final String name);
+}
diff --git a/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/AptUploadHandler.java b/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/AptUploadHandler.java
index c92aaca8b2..49a03643ee 100644
--- a/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/AptUploadHandler.java
+++ b/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/AptUploadHandler.java
@@ -63,7 +63,7 @@ public AptUploadHandler(@Named("simple") final VariableResolverAdapter variableR
}
@Override
- public UploadResponse handle(Repository repository, ComponentUpload upload) throws IOException {
+ public UploadResponse handle(final Repository repository, final ComponentUpload upload) throws IOException {
AptHostedFacet hostedFacet = repository.facet(AptHostedFacet.class);
StorageFacet storageFacet = repository.facet(StorageFacet.class);
diff --git a/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/internal/AptBrowseNodeGenerator.java b/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/internal/AptBrowseNodeGenerator.java
index 0dc9b9cbf0..85a6fd6763 100644
--- a/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/internal/AptBrowseNodeGenerator.java
+++ b/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/internal/AptBrowseNodeGenerator.java
@@ -37,7 +37,7 @@ public class AptBrowseNodeGenerator
{
@Override
- public List computeAssetPath(Asset asset, Component component) {
+ public List computeAssetPath(final Asset asset, final Component component) {
List path;
if (component != null) {
path = computeComponentPath(asset, component);
@@ -57,7 +57,7 @@ public List computeAssetPath(Asset asset, Component component) {
}
@Override
- public List computeComponentPath(Asset asset, Component component) {
+ public List computeComponentPath(final Asset asset, final Component component) {
List path = new ArrayList<>();
path.add("packages");
path.add(component.name().substring(0, 1).toLowerCase());
diff --git a/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/internal/AptComponentDirector.java b/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/internal/AptComponentDirector.java
new file mode 100644
index 0000000000..cc8912c001
--- /dev/null
+++ b/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/internal/AptComponentDirector.java
@@ -0,0 +1,98 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2008-present Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+package org.sonatype.nexus.repository.apt.internal;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.sonatype.goodies.common.ComponentSupport;
+import org.sonatype.nexus.repository.Repository;
+import org.sonatype.nexus.repository.apt.internal.hosted.AptHostedFacet;
+import org.sonatype.nexus.repository.manager.RepositoryManager;
+import org.sonatype.nexus.repository.storage.Bucket;
+import org.sonatype.nexus.repository.storage.BucketStore;
+import org.sonatype.nexus.repository.storage.Component;
+import org.sonatype.nexus.repository.storage.ComponentDirector;
+import org.sonatype.nexus.repository.storage.StorageFacet;
+import org.sonatype.nexus.transaction.UnitOfWork;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * @since 3.next
+ */
+@Named(AptFormat.NAME)
+@Singleton
+public class AptComponentDirector
+ extends ComponentSupport
+ implements ComponentDirector
+{
+ private final BucketStore bucketStore;
+
+ private final RepositoryManager repositoryManager;
+
+ @Inject
+ public AptComponentDirector(final BucketStore bucketStore,
+ final RepositoryManager repositoryManager)
+ {
+ this.bucketStore = checkNotNull(bucketStore);
+ this.repositoryManager = checkNotNull(repositoryManager);
+ }
+
+ @Override
+ public boolean allowMoveTo(final Repository destination) {
+ return true;
+ }
+
+ @Override
+ public boolean allowMoveTo(final Component component, final Repository destination) {
+ return repositoryFor(component).isPresent();
+ }
+
+ @Override
+ public boolean allowMoveFrom(final Repository source) {
+ return true;
+ }
+
+ @Override
+ public void afterMove(final List