conjur-asset-ui-beta 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. checksums.yaml +7 -0
  2. data/.git-hooks/pre_commit/trailing_whitespace.rb +26 -0
  3. data/.gitignore +23 -0
  4. data/.project +18 -0
  5. data/CHANGELOG.md +14 -0
  6. data/Gemfile +10 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +72 -0
  9. data/Rakefile +76 -0
  10. data/TODO.md +31 -0
  11. data/app/.csscomb.json +304 -0
  12. data/app/.jshintrc +46 -0
  13. data/app/build/css/bootstrap.css +6906 -0
  14. data/app/build/fonts/glyphicons-halflings-regular.eot +0 -0
  15. data/app/build/fonts/glyphicons-halflings-regular.svg +288 -0
  16. data/app/build/fonts/glyphicons-halflings-regular.ttf +0 -0
  17. data/app/build/fonts/glyphicons-halflings-regular.woff +0 -0
  18. data/app/build/fonts/glyphicons-halflings-regular.woff2 +0 -0
  19. data/app/build/images/conjur-logo.svg +26 -0
  20. data/app/build/images/icon-client-pc.svg +12 -0
  21. data/app/build/images/icon-environment.png +0 -0
  22. data/app/build/images/icon-person.svg +12 -0
  23. data/app/build/images/icon-policy.png +0 -0
  24. data/app/build/images/icon-resource.png +0 -0
  25. data/app/build/images/icon-service-dots.svg +13 -0
  26. data/app/build/images/icon-variable.png +0 -0
  27. data/app/build/index.html +26 -0
  28. data/app/build/js/app.js +78070 -0
  29. data/app/build/js/pace.js +2 -0
  30. data/app/config/preprocessor.js +9 -0
  31. data/app/config/webpack.js +84 -0
  32. data/app/gulpfile.js +144 -0
  33. data/app/package.json +83 -0
  34. data/app/src/actions.js +493 -0
  35. data/app/src/app.js +76 -0
  36. data/app/src/clients/audit.js +54 -0
  37. data/app/src/clients/generic.js +87 -0
  38. data/app/src/clients/layer_members.js +36 -0
  39. data/app/src/clients/list.js +82 -0
  40. data/app/src/clients/members.js +37 -0
  41. data/app/src/clients/search.js +19 -0
  42. data/app/src/components/app/__tests__/app-test.js +22 -0
  43. data/app/src/components/app/app.js +66 -0
  44. data/app/src/components/audit/__tests__/table_header-test.js +40 -0
  45. data/app/src/components/audit/box.js +11 -0
  46. data/app/src/components/audit/constants.js +7 -0
  47. data/app/src/components/audit/entry.js +107 -0
  48. data/app/src/components/audit/fields_mixin.js +13 -0
  49. data/app/src/components/audit/humanize_event.js +216 -0
  50. data/app/src/components/audit/table.js +100 -0
  51. data/app/src/components/audit/table_header.js +38 -0
  52. data/app/src/components/audit/timestamp.js +30 -0
  53. data/app/src/components/chart/chart.js +539 -0
  54. data/app/src/components/chart/chart_helper_mixin.js +79 -0
  55. data/app/src/components/custom/list.js +5 -0
  56. data/app/src/components/custom/view.js +71 -0
  57. data/app/src/components/dashboard/activity.js +113 -0
  58. data/app/src/components/dashboard/dashboard.js +47 -0
  59. data/app/src/components/flash/flash.js +17 -0
  60. data/app/src/components/generic/__tests__/time-test.js +43 -0
  61. data/app/src/components/generic/annotations.js +41 -0
  62. data/app/src/components/generic/breadcrumbs.js +59 -0
  63. data/app/src/components/generic/foldable_audit_section.js +252 -0
  64. data/app/src/components/generic/list.js +144 -0
  65. data/app/src/components/generic/list_factory.js +42 -0
  66. data/app/src/components/generic/resource_link.js +65 -0
  67. data/app/src/components/generic/role_link.js +65 -0
  68. data/app/src/components/generic/tab_mixin.js +148 -0
  69. data/app/src/components/generic/time.js +34 -0
  70. data/app/src/components/group/list.js +5 -0
  71. data/app/src/components/group/view.js +137 -0
  72. data/app/src/components/host/activity.js +93 -0
  73. data/app/src/components/host/details.js +30 -0
  74. data/app/src/components/host/host_link.js +20 -0
  75. data/app/src/components/host/list.js +5 -0
  76. data/app/src/components/host/view.js +113 -0
  77. data/app/src/components/layer/list.js +5 -0
  78. data/app/src/components/layer/view.js +180 -0
  79. data/app/src/components/navbar/__tests__/navbar-test.js +21 -0
  80. data/app/src/components/navbar/nav_search_form.js +41 -0
  81. data/app/src/components/navbar/navbar.js +71 -0
  82. data/app/src/components/owned_resources/owned_resources.js +86 -0
  83. data/app/src/components/owned_resources/owned_resources_box.js +106 -0
  84. data/app/src/components/permissions/permissions.js +143 -0
  85. data/app/src/components/permissions/permissions_table.js +104 -0
  86. data/app/src/components/policy/list.js +5 -0
  87. data/app/src/components/policy/view.js +98 -0
  88. data/app/src/components/refresh/refresh.js +30 -0
  89. data/app/src/components/refresh/refresh.less +15 -0
  90. data/app/src/components/search/group.js +45 -0
  91. data/app/src/components/search/group_heading.js +50 -0
  92. data/app/src/components/search/group_title.js +38 -0
  93. data/app/src/components/search/result_item.js +57 -0
  94. data/app/src/components/search/search.js +103 -0
  95. data/app/src/components/user/activity.js +92 -0
  96. data/app/src/components/user/details.js +30 -0
  97. data/app/src/components/user/list.js +5 -0
  98. data/app/src/components/user/pubkeys.js +116 -0
  99. data/app/src/components/user/pubkeys.less +56 -0
  100. data/app/src/components/user/view.js +123 -0
  101. data/app/src/components/variable/activity.js +83 -0
  102. data/app/src/components/variable/details.js +48 -0
  103. data/app/src/components/variable/fetchers.js +83 -0
  104. data/app/src/components/variable/list.js +5 -0
  105. data/app/src/components/variable/updaters.js +83 -0
  106. data/app/src/components/variable/view.js +105 -0
  107. data/app/src/constants.js +35 -0
  108. data/app/src/images/conjur-logo.svg +26 -0
  109. data/app/src/images/icon-client-pc.svg +12 -0
  110. data/app/src/images/icon-environment.png +0 -0
  111. data/app/src/images/icon-person.svg +12 -0
  112. data/app/src/images/icon-policy.png +0 -0
  113. data/app/src/images/icon-resource.png +0 -0
  114. data/app/src/images/icon-service-dots.svg +13 -0
  115. data/app/src/images/icon-variable.png +0 -0
  116. data/app/src/pages/index.html +26 -0
  117. data/app/src/routes.js +57 -0
  118. data/app/src/stores/app_store.js +29 -0
  119. data/app/src/stores/audit_store.js +77 -0
  120. data/app/src/stores/group_store.js +105 -0
  121. data/app/src/stores/host_store.js +98 -0
  122. data/app/src/stores/layer_store.js +115 -0
  123. data/app/src/stores/policy_store.js +89 -0
  124. data/app/src/stores/resources_store.js +118 -0
  125. data/app/src/stores/route_store.js +24 -0
  126. data/app/src/stores/search_store.js +73 -0
  127. data/app/src/stores/user_store.js +111 -0
  128. data/app/src/stores/variable_store.js +94 -0
  129. data/app/src/styles/bootstrap.less +56 -0
  130. data/app/src/styles/styles.less +634 -0
  131. data/app/src/utils.js +43 -0
  132. data/app/src/vendor/pace.js +2 -0
  133. data/conjur-asset-ui.gemspec +36 -0
  134. data/features/navigation_bar.feature +31 -0
  135. data/features/step_definitions/custom_step.rb +32 -0
  136. data/features/support/env.rb +38 -0
  137. data/features/support/hooks.rb +30 -0
  138. data/features/support/world.rb +17 -0
  139. data/lib/conjur-asset-ui-version.rb +7 -0
  140. data/lib/conjur-asset-ui.rb +7 -0
  141. data/lib/conjur/command/ui.rb +54 -0
  142. data/lib/conjur/webserver/api_proxy.rb +94 -0
  143. data/lib/conjur/webserver/authorize.rb +28 -0
  144. data/lib/conjur/webserver/conjur_info.rb +33 -0
  145. data/lib/conjur/webserver/home.rb +42 -0
  146. data/lib/conjur/webserver/login.rb +57 -0
  147. data/lib/conjur/webserver/renderer.rb +34 -0
  148. data/lib/conjur/webserver/server.rb +130 -0
  149. data/public/js/views/roleGraph.js +91 -0
  150. metadata +373 -0
@@ -0,0 +1,79 @@
1
+ 'use strict';
2
+
3
+ var d3 = require('d3'),
4
+ forEach = require('lodash/collection/forEach');
5
+
6
+ var oneDay = 86400000;
7
+
8
+ module.exports = {
9
+ getData(audit) {
10
+ var values = {},
11
+ min,
12
+ max,
13
+ self = this;
14
+
15
+ forEach(audit, function(e) {
16
+ var date,
17
+ type,
18
+ value;
19
+
20
+ if (typeof e.timestamp === 'string') {
21
+ date = d3.time.hour(new Date(e.timestamp));
22
+ }
23
+
24
+ type = self.getEventType(e);
25
+
26
+ if (date instanceof Date && typeof type === 'string') {
27
+ value = values[date.toString()];
28
+
29
+ if (typeof value === 'undefined') {
30
+ value = self.getDefaultItem();
31
+ value.date = date;
32
+ }
33
+
34
+ value[type] = value[type] + 1;
35
+
36
+ values[date.toString()] = value;
37
+
38
+ if (typeof max === 'undefined') {
39
+ max = date;
40
+ }
41
+
42
+ if (typeof min === 'undefined') {
43
+ min = date;
44
+ }
45
+
46
+ if (date > max) {
47
+ max = date;
48
+ }
49
+
50
+ if (date < min) {
51
+ min = date;
52
+ }
53
+ }
54
+ });
55
+
56
+ var x = max - min;
57
+
58
+ if (x < oneDay) {
59
+ var delta = Math.round((86400000 - x) / 2);
60
+
61
+ min = new Date(min.getTime() - delta);
62
+ max = new Date(max.getTime() + delta);
63
+ }
64
+
65
+ return d3.time.scale()
66
+ .domain([min, max])
67
+ .ticks(d3.time.hours, 1)
68
+ .map(function(date) {
69
+ var d = values[date.toString()] || self.getDefaultItem();
70
+
71
+ d.date = date;
72
+
73
+ return d;
74
+ })
75
+ .sort(function(a, b) {
76
+ return a.date - b.date;
77
+ });
78
+ }
79
+ };
@@ -0,0 +1,5 @@
1
+ 'use strict';
2
+
3
+ var genericListFactory = require('../generic/list_factory');
4
+
5
+ module.exports = genericListFactory('custom-type', 'Custom Types');
@@ -0,0 +1,71 @@
1
+ 'use strict';
2
+
3
+ var React = require('react'),
4
+ Fluxxor = require('fluxxor'),
5
+ FluxMixin = Fluxxor.FluxMixin(React),
6
+ StoreWatchMixin = Fluxxor.StoreWatchMixin,
7
+ Router = require('react-router');
8
+
9
+ var AuditTable = require('../audit/table'),
10
+ Annotations = require('../generic/annotations'),
11
+ Breadcrumbs = require('../generic/breadcrumbs'),
12
+ FoldableAuditSection = require('../generic/foldable_audit_section'),
13
+ Refresh = require('../refresh/refresh');
14
+
15
+ module.exports = React.createClass({
16
+ displayName: 'CustomView',
17
+
18
+ mixins: [FluxMixin, StoreWatchMixin('audit', 'resources'), Router.State],
19
+
20
+ getStateFromFlux() {
21
+ var flux = this.getFlux(),
22
+ kind = unescape(this.getParams().kind),
23
+ id = unescape(this.getParams().id),
24
+ audit = flux.store('audit').getEventFor(kind, id),
25
+ resource = flux.store('resources').getResource(kind, id);
26
+
27
+ return {
28
+ loading: {
29
+ audit: audit.loading,
30
+ resource: resource.loading
31
+ },
32
+ error: {
33
+ resource: resource.error
34
+ },
35
+ audit: audit.data,
36
+ resource: resource.data
37
+ };
38
+ },
39
+
40
+ render() {
41
+ var elems = [
42
+ {url: '/ui/custom-types', text: 'Custom Types'},
43
+ {url: '', text: this.state.resource.id},
44
+ {url: '', text: '(owned by ' + this.state.resource.owner + ')'}
45
+ ];
46
+
47
+ return (
48
+ <div className="b-variable">
49
+ <Breadcrumbs elems={elems} />
50
+ <hr />
51
+ <h2>Custom Type {this.state.resource.kind}:{this.state.resource.identifier}</h2>
52
+ <hr/>
53
+ <h2>Annotations<Refresh show={this.state.loading.resource} /></h2>
54
+ <Annotations annotations={this.state.resource.annotations} />
55
+ <hr />
56
+ <AuditTable events={this.state.audit}
57
+ caption="Recent Activity"
58
+ isLoading={this.state.loading.audit} />
59
+ </div>
60
+ );
61
+ },
62
+
63
+ componentDidMount() {
64
+ var actions = this.getFlux().actions,
65
+ kind = unescape(this.getParams().kind),
66
+ id = unescape(this.getParams().id);
67
+
68
+ actions.audit.loadForResource(kind, id);
69
+ actions.resources.loadOne(kind, id);
70
+ }
71
+ });
@@ -0,0 +1,113 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+
5
+ var Chart = require('../chart/chart'),
6
+ ChartHelperMixin = require('../chart/chart_helper_mixin'),
7
+ Refresh = require('../refresh/refresh');
8
+
9
+ module.exports = React.createClass({
10
+ displayName: 'DashboardActivity',
11
+
12
+ mixins: [ChartHelperMixin],
13
+
14
+ getDefaultProps() {
15
+ return {
16
+ options: {
17
+ legend: {
18
+ slogins: 'Logins',
19
+ ssudo: 'Sudo calls',
20
+ sreads: 'Secret reads',
21
+ supdates: 'Secret updates',
22
+ fsudo: 'Sudo failures',
23
+ freads: 'Secret read failures',
24
+ fupdates: 'Secret update failures',
25
+ fother: 'Other failures'
26
+ },
27
+ axis: {
28
+ y: {
29
+ label: 'Value'
30
+ }
31
+ }
32
+ }
33
+ };
34
+ },
35
+
36
+ getDefaultItem() {
37
+ return {
38
+ slogins: 0,
39
+ ssudo: 0,
40
+ fsudo: 0,
41
+ sreads: 0,
42
+ freads: 0,
43
+ supdates: 0,
44
+ fupdates: 0,
45
+ fother: 0
46
+ };
47
+ },
48
+
49
+ getEventType(e) {
50
+ if (e.hasOwnProperty('facility') && e.facility === 'ssh') {
51
+ if (e.allowed === true) {
52
+ if (e.action === 'sudo') {
53
+ return 'ssudo';
54
+ }
55
+
56
+ if (e.action === 'login') {
57
+ return 'slogins';
58
+ }
59
+ }
60
+
61
+ if (e.allowed === false) {
62
+ if (e.action === 'sudo') {
63
+ return 'fsudo';
64
+ }
65
+ }
66
+ }
67
+
68
+ if ((e.action === 'check') &&
69
+ e.hasOwnProperty('resource') &&
70
+ e.resource.split(':')[1] === 'variable') {
71
+
72
+ if (e.hasOwnProperty('error') || e.allowed === false) {
73
+ if (e.privilege === 'execute') {
74
+ return 'freads';
75
+ }
76
+
77
+ if (e.privilege === 'update') {
78
+ return 'fupdates';
79
+ }
80
+ }
81
+
82
+ if (!e.hasOwnProperty('error') && e.allowed !== false) {
83
+ if (e.privilege === 'execute') {
84
+ return 'sreads';
85
+ }
86
+
87
+ if (e.privilege === 'update') {
88
+ return 'supdates';
89
+ }
90
+ }
91
+ }
92
+
93
+ if (e.hasOwnProperty('error') || e.allowed === false) {
94
+ return 'fother';
95
+ }
96
+
97
+ return null;
98
+ },
99
+
100
+ render() {
101
+ var data = this.getData(this.props.audit);
102
+
103
+ return (
104
+ <div className="b-dashboard-activity">
105
+ <h2>Activity<Refresh show={this.props.isLoading} /></h2>
106
+ <div className="b-dashboard-activity__graph">
107
+ <Chart options={this.props.options}
108
+ data={data} />
109
+ </div>
110
+ </div>
111
+ );
112
+ }
113
+ });
@@ -0,0 +1,47 @@
1
+ 'use strict';
2
+
3
+ var React = require('react'),
4
+ Fluxxor = require('fluxxor'),
5
+ FluxMixin = Fluxxor.FluxMixin(React),
6
+ StoreWatchMixin = Fluxxor.StoreWatchMixin;
7
+
8
+ var AuditTable = require('../audit/table'),
9
+ FoldableAuditSection = require('../generic/foldable_audit_section');
10
+
11
+ var Activity = require('./activity');
12
+
13
+ module.exports = React.createClass({
14
+ displayName: 'Dashboard',
15
+
16
+ mixins: [FluxMixin, StoreWatchMixin('audit')],
17
+
18
+ getStateFromFlux() {
19
+ var audit = this.getFlux().store('audit').getAllEvents();
20
+
21
+ return {
22
+ audit: audit.data,
23
+ loading: audit.loading
24
+ };
25
+ },
26
+
27
+ render() {
28
+ return (
29
+ <div className="b-dashboard">
30
+ <Activity audit={this.state.audit}
31
+ isLoading={this.state.loading} />
32
+ <hr />
33
+ {FoldableAuditSection.warnings(this.state.audit, this.state.loading)}
34
+ <hr />
35
+ {FoldableAuditSection.changes(this.state.audit, this.state.loading)}
36
+ <hr />
37
+ <AuditTable events={this.state.audit}
38
+ caption="Recent activity"
39
+ isLoading={this.state.loading} />
40
+ </div>
41
+ );
42
+ },
43
+
44
+ componentDidMount() {
45
+ this.getFlux().actions.audit.loadAll();
46
+ }
47
+ });
@@ -0,0 +1,17 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+
5
+ module.exports = React.createClass({
6
+ displayName: 'Flash',
7
+
8
+ render() {
9
+ return (
10
+ <div className="alert alert-danger alert-dismissable">
11
+ <button type="button" className="close" aria-hidden="true"
12
+ onClick={this.props.handleClose}>×</button>
13
+ <span className="text">{this.props.msg}</span>
14
+ </div>
15
+ );
16
+ }
17
+ });
@@ -0,0 +1,43 @@
1
+ /* global jest, describe, it, expect */
2
+
3
+ 'use strict';
4
+
5
+ jest.dontMock('../time');
6
+ jest.dontMock('moment');
7
+
8
+ var React = require('react/addons'),
9
+ TestUtils = React.addons.TestUtils,
10
+ Time = require('../time').Time;
11
+
12
+ describe('time', function() {
13
+ it('default render', function() {
14
+ var component = TestUtils.renderIntoDocument(
15
+ <Time timestamp="1" />
16
+ );
17
+
18
+ var element = TestUtils.findRenderedDOMComponentWithTag(component, 'time');
19
+
20
+ expect(element.getDOMNode().textContent).toEqual('Jan 1, 1970 3:00 AM');
21
+ });
22
+
23
+
24
+ it('time from now', function() {
25
+ var component = TestUtils.renderIntoDocument(
26
+ <Time timestamp="1" relative="time from now" />
27
+ );
28
+
29
+ var element = TestUtils.findRenderedDOMComponentWithTag(component, 'time');
30
+
31
+ expect(element.getDOMNode().textContent).toMatch(/years ago/);
32
+ });
33
+
34
+ it('calendar time', function() {
35
+ var component = TestUtils.renderIntoDocument(
36
+ <Time timestamp="1" relative="calendar time" />
37
+ );
38
+
39
+ var element = TestUtils.findRenderedDOMComponentWithTag(component, 'time');
40
+
41
+ expect(element.getDOMNode().textContent).toEqual('01/01/1970');
42
+ });
43
+ });
@@ -0,0 +1,41 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+
5
+ module.exports = React.createClass({
6
+ displayName: 'GenericAnnotations',
7
+
8
+ render() {
9
+ if (!this.props.annotations || this.props.annotations.length === 0) {
10
+ return (
11
+ <div>
12
+ <span>None</span>
13
+ </div>
14
+ );
15
+ }
16
+
17
+ // TODO: sort by date (optionally)
18
+ // TODO: table view
19
+ var annotationsList = [];
20
+
21
+ this.props.annotations.sort(function(a, b) {
22
+ return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
23
+ }).forEach(function(item) {
24
+ var itemName = item.name,
25
+ itemValue = item.value,
26
+ term = 'annotation_' + itemName + '_key',
27
+ description = 'annotation_' + itemName + '_value';
28
+
29
+ annotationsList.push(<dt key={term}>{itemName}</dt>);
30
+ annotationsList.push(<dd key={description}>{itemValue}</dd>);
31
+ });
32
+
33
+ return (
34
+ <div>
35
+ <dl className="annotations">
36
+ {annotationsList}
37
+ </dl>
38
+ </div>
39
+ );
40
+ }
41
+ });
@@ -0,0 +1,59 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+
5
+ var map = require('lodash/collection/map');
6
+
7
+ var Breadcrumb = React.createClass({
8
+ displayName: 'Breadcrumb',
9
+
10
+ render() {
11
+ var className = '',
12
+ text;
13
+
14
+ if (this.props.active === true) {
15
+ className = 'active';
16
+ text = this.props.text;
17
+
18
+ } else if (this.props.extra === true) {
19
+ className = 'b-breadcrumb__extra';
20
+ text = this.props.text;
21
+ } else {
22
+ text = (<a href={this.props.url}>{this.props.text}</a>);
23
+ }
24
+
25
+ return (
26
+ <li className={className}>
27
+ {text}
28
+ </li>
29
+ );
30
+ }
31
+ });
32
+
33
+ module.exports = React.createClass({
34
+ displayName: 'Breadcrumbs',
35
+
36
+ render() {
37
+ var items = map(this.props.elems || [], function(e, idx, coll) {
38
+ var length = coll.length - 1,
39
+ active = idx + 1 === length ? true : false,
40
+ extra = idx === length ? true : false;
41
+
42
+ return (
43
+ <Breadcrumb url={e.url}
44
+ text={e.text}
45
+ active={active}
46
+ extra={extra}
47
+ key={e.url + e.text} />
48
+ );
49
+ });
50
+
51
+ return (
52
+ <div className="b-breadcrumbs">
53
+ <ol className="breadcrumb">
54
+ {items}
55
+ </ol>
56
+ </div>
57
+ );
58
+ }
59
+ });