diff --git a/addons/api/addon/generated/models/target.js b/addons/api/addon/generated/models/target.js
index d363a9d03..86605800c 100644
--- a/addons/api/addon/generated/models/target.js
+++ b/addons/api/addon/generated/models/target.js
@@ -108,4 +108,10 @@ export default class GeneratedTargetModel extends BaseModel {
isNestedAttribute: true,
})
enable_session_recording;
+
+ @attr('array', {
+ description:
+ 'with_aliases specify the aliases that should be created when the target is created. ',
+ })
+ with_aliases;
}
diff --git a/addons/api/addon/models/role.js b/addons/api/addon/models/role.js
index b0d56e6b7..e574eb7e7 100644
--- a/addons/api/addon/models/role.js
+++ b/addons/api/addon/models/role.js
@@ -27,7 +27,7 @@ export default class RoleModel extends GeneratedRoleModel {
* see obvious. Instead, the application layer is expected to load referenced
* users and groups as needed.
*/
- @attr('principal-array', {
+ @attr('array', {
readOnly: true,
emptyArrayIfMissing: true,
})
@@ -55,7 +55,7 @@ export default class RoleModel extends GeneratedRoleModel {
get userIDs() {
return this.principals
.filter(({ type }) => type === 'user')
- .map(({ principal_id }) => principal_id);
+ .map(({ id }) => id);
}
/**
@@ -65,7 +65,7 @@ export default class RoleModel extends GeneratedRoleModel {
get groupIDs() {
return this.principals
.filter(({ type }) => type === 'group')
- .map(({ principal_id }) => principal_id);
+ .map(({ id }) => id);
}
/**
@@ -75,7 +75,7 @@ export default class RoleModel extends GeneratedRoleModel {
get managedGroupIDs() {
return this.principals
.filter(({ type }) => type === 'managed group')
- .map(({ principal_id }) => principal_id);
+ .map(({ id }) => id);
}
/**
diff --git a/addons/api/addon/serializers/target.js b/addons/api/addon/serializers/target.js
index 17a00ced5..d667e3ab9 100644
--- a/addons/api/addon/serializers/target.js
+++ b/addons/api/addon/serializers/target.js
@@ -44,6 +44,14 @@ export default class TargetSerializer extends ApplicationSerializer {
injectedApplicationCredentialSourceIDs,
);
+ if (serialized?.with_aliases) {
+ // API expects scope id along with every alias value
+ serialized.with_aliases = serialized.with_aliases.map((item) => ({
+ ...item,
+ scope_id: 'global',
+ }));
+ }
+
// Delete session recording related fields from non-SSH targets
if (type !== TYPE_TARGET_SSH) {
delete serialized?.attributes?.storage_bucket_id;
diff --git a/addons/api/addon/transforms/array.js b/addons/api/addon/transforms/array.js
new file mode 100644
index 000000000..7df725a1e
--- /dev/null
+++ b/addons/api/addon/transforms/array.js
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: MPL-2.0
+ */
+
+import Transform from '@ember-data/serializer/transform';
+import { TrackedArray } from 'tracked-built-ins';
+
+export default class ArrayTransform extends Transform {
+ deserialize(serialized) {
+ const arr = new TrackedArray(serialized || []);
+ return arr;
+ }
+
+ serialize(deserialized) {
+ const arr = deserialized || [];
+ return arr;
+ }
+}
diff --git a/addons/api/addon/transforms/principal-array.js b/addons/api/addon/transforms/principal-array.js
deleted file mode 100644
index 07f7aa551..000000000
--- a/addons/api/addon/transforms/principal-array.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * Copyright (c) HashiCorp, Inc.
- * SPDX-License-Identifier: MPL-2.0
- */
-
-import Transform from '@ember-data/serializer/transform';
-
-export default class PrincipalArrayTransform extends Transform {
- deserialize(serialized) {
- const stringValues = serialized || [];
- return stringValues.map(({ id: principal_id, scope_id, type }) => ({
- principal_id,
- scope_id,
- type,
- }));
- }
-
- serialize(deserialized) {
- const strings = deserialized || [];
- return strings.map(({ principal_id: id, scope_id, type }) => ({
- id,
- scope_id,
- type,
- }));
- }
-}
diff --git a/addons/api/app/transforms/principal-array.js b/addons/api/app/transforms/array.js
similarity index 57%
rename from addons/api/app/transforms/principal-array.js
rename to addons/api/app/transforms/array.js
index 5a644f5ba..4a049828f 100644
--- a/addons/api/app/transforms/principal-array.js
+++ b/addons/api/app/transforms/array.js
@@ -3,4 +3,4 @@
* SPDX-License-Identifier: MPL-2.0
*/
-export { default } from 'api/transforms/principal-array';
+export { default } from 'api/transforms/array';
diff --git a/addons/api/tests/unit/serializers/target-test.js b/addons/api/tests/unit/serializers/target-test.js
index 76dd6599b..bc6fa8739 100644
--- a/addons/api/tests/unit/serializers/target-test.js
+++ b/addons/api/tests/unit/serializers/target-test.js
@@ -36,6 +36,7 @@ module('Unit | Serializer | target', function (hooks) {
address: '0.0.0.0',
enable_session_recording: false,
storage_bucket_id: null,
+ with_aliases: [{ value: 'a' }],
});
const snapshot = record._createSnapshot();
snapshot.adapterOptions = {};
@@ -51,6 +52,7 @@ module('Unit | Serializer | target', function (hooks) {
worker_filter: null,
egress_worker_filter: null,
ingress_worker_filter: null,
+ with_aliases: [{ value: 'a', scope_id: 'global' }],
attributes: {
default_port: 1234,
default_client_port: 4321,
@@ -85,6 +87,7 @@ module('Unit | Serializer | target', function (hooks) {
enable_session_recording: false,
storage_bucket_id: null,
address: '0.0.0.0',
+ with_aliases: [{ value: 'www.test.com' }],
});
const snapshot = record._createSnapshot();
snapshot.adapterOptions = {};
@@ -100,6 +103,7 @@ module('Unit | Serializer | target', function (hooks) {
worker_filter: null,
egress_worker_filter: null,
ingress_worker_filter: null,
+ with_aliases: [{ value: 'www.test.com', scope_id: 'global' }],
attributes: {
default_port: 1234,
default_client_port: 4321,
@@ -189,6 +193,7 @@ module('Unit | Serializer | target', function (hooks) {
enable_session_recording: true,
storage_bucket_id: 'bucketID',
default_port: 1234,
+ with_aliases: [],
scope: {
scope_id: 'org_1',
},
@@ -206,6 +211,7 @@ module('Unit | Serializer | target', function (hooks) {
worker_filter: null,
egress_worker_filter: null,
ingress_worker_filter: null,
+ with_aliases: [],
attributes: {
default_port: 1234,
default_client_port: null,
@@ -226,6 +232,7 @@ module('Unit | Serializer | target', function (hooks) {
type: TYPE_TARGET_SSH,
worker_filter: 'worker',
default_port: 1234,
+ with_aliases: [],
scope: {
scope_id: 'org_1',
},
@@ -243,6 +250,7 @@ module('Unit | Serializer | target', function (hooks) {
worker_filter: 'worker',
egress_worker_filter: null,
ingress_worker_filter: null,
+ with_aliases: [],
attributes: {
default_port: 1234,
default_client_port: null,
@@ -263,6 +271,7 @@ module('Unit | Serializer | target', function (hooks) {
type: TYPE_TARGET_SSH,
egress_worker_filter: 'egress worker',
default_port: 1234,
+ with_aliases: [],
scope: {
scope_id: 'org_1',
},
@@ -280,6 +289,7 @@ module('Unit | Serializer | target', function (hooks) {
worker_filter: null,
egress_worker_filter: 'egress worker',
ingress_worker_filter: null,
+ with_aliases: [],
attributes: {
default_port: 1234,
default_client_port: null,
@@ -300,6 +310,7 @@ module('Unit | Serializer | target', function (hooks) {
type: TYPE_TARGET_SSH,
ingress_worker_filter: 'ingress worker',
default_port: 1234,
+ with_aliases: [],
scope: {
scope_id: 'org_1',
},
@@ -317,6 +328,7 @@ module('Unit | Serializer | target', function (hooks) {
worker_filter: null,
egress_worker_filter: null,
ingress_worker_filter: 'ingress worker',
+ with_aliases: [],
attributes: {
default_port: 1234,
default_client_port: null,
diff --git a/addons/api/tests/unit/transforms/array-test.js b/addons/api/tests/unit/transforms/array-test.js
new file mode 100644
index 000000000..a2ccc3b78
--- /dev/null
+++ b/addons/api/tests/unit/transforms/array-test.js
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: MPL-2.0
+ */
+
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Transform | array', function (hooks) {
+ setupTest(hooks);
+
+ test('it serializes a principals array', function (assert) {
+ const transform = this.owner.lookup('transform:array');
+ const principal = [
+ { id: 2, type: 'user' },
+ { id: 3, type: 'group' },
+ { id: 3, type: 'managed-group' },
+ ];
+ const expectedArr = [
+ { id: 2, type: 'user' },
+ { id: 3, type: 'group' },
+ { id: 3, type: 'managed-group' },
+ ];
+ const emptyArr = [];
+ assert.deepEqual(transform.serialize(principal), expectedArr);
+ assert.deepEqual(transform.serialize(emptyArr), []);
+ });
+
+ test('it deserializes a principals array', function (assert) {
+ const transform = this.owner.lookup('transform:array');
+ const principal = [
+ { id: 2, type: 'user' },
+ { id: 3, type: 'group' },
+ { id: 3, type: 'managed-group' },
+ ];
+ const expectedArr = [
+ { id: 2, type: 'user' },
+ { id: 3, type: 'group' },
+ { id: 3, type: 'managed-group' },
+ ];
+ const emptyArr = [];
+ assert.deepEqual(transform.deserialize(principal), expectedArr);
+ assert.deepEqual(transform.deserialize(emptyArr), []);
+ });
+});
diff --git a/addons/api/tests/unit/transforms/principal-array-test.js b/addons/api/tests/unit/transforms/principal-array-test.js
deleted file mode 100644
index 3628e465b..000000000
--- a/addons/api/tests/unit/transforms/principal-array-test.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * Copyright (c) HashiCorp, Inc.
- * SPDX-License-Identifier: MPL-2.0
- */
-
-import { module, test } from 'qunit';
-import { setupTest } from 'ember-qunit';
-
-module('Unit | Transform | principal array', function (hooks) {
- setupTest(hooks);
-
- // Replace this with your real tests.
- test('it exists', function (assert) {
- let transform = this.owner.lookup('transform:principal-array');
- assert.ok(transform);
- });
-});
diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml
index 85d29cef2..a897f54e5 100644
--- a/addons/core/translations/resources/en-us.yaml
+++ b/addons/core/translations/resources/en-us.yaml
@@ -1027,3 +1027,6 @@ alias:
authorize_session_arguments:
label: Host ID
help: Always use this host when connecting using this alias
+ alias:
+ label: Aliases
+ help: You can create aliases for this target that will make it easier to reach. Users must have access to this project to use aliases.
diff --git a/ui/admin/app/components/form/role/add-principals/index.js b/ui/admin/app/components/form/role/add-principals/index.js
index d79322acb..a91cabcca 100644
--- a/ui/admin/app/components/form/role/add-principals/index.js
+++ b/ui/admin/app/components/form/role/add-principals/index.js
@@ -35,7 +35,7 @@ export default class FormRoleAddPrincipalsIndexComponent extends Component {
get filteredPrincipals() {
// Retrieve principal IDs assigned to current role
const currentPrincipalIDs = this.args.model.principals.map(
- (principal) => principal.principal_id,
+ (principal) => principal.id,
);
// Retrieve principal IDs not assigned to current role
diff --git a/ui/admin/app/components/form/target/details/index.hbs b/ui/admin/app/components/form/target/details/index.hbs
index 91e247e64..29f0d99b3 100644
--- a/ui/admin/app/components/form/target/details/index.hbs
+++ b/ui/admin/app/components/form/target/details/index.hbs
@@ -325,6 +325,42 @@
{{/if}}
+ {{#if
+ (and @model.isNew (can 'create model' @globalScope collection='aliases'))
+ }}
+
+
{{t 'resources.target.description'}}
-