conjur-asset-ui-api 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +7 -0
  2. data/.git-hooks/pre_commit/ensure_livescript_compiled.rb +31 -0
  3. data/.git-hooks/pre_commit/trailing_whitespace.rb +26 -0
  4. data/.gitignore +20 -0
  5. data/.overcommit.yml +5 -0
  6. data/.project +18 -0
  7. data/Gemfile +8 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +41 -0
  10. data/Rakefile +1 -0
  11. data/compile_ls +2 -0
  12. data/conjur-asset-ui.gemspec +36 -0
  13. data/lib/conjur-asset-ui-version.rb +7 -0
  14. data/lib/conjur-asset-ui.rb +7 -0
  15. data/lib/conjur/audit/follower.rb +63 -0
  16. data/lib/conjur/audit/humanizer.rb +53 -0
  17. data/lib/conjur/audit/tableizer.rb +55 -0
  18. data/lib/conjur/command/ui.rb +38 -0
  19. data/lib/conjur/webserver/api_proxy.rb +94 -0
  20. data/lib/conjur/webserver/audit_stream.rb +92 -0
  21. data/lib/conjur/webserver/authorize.rb +28 -0
  22. data/lib/conjur/webserver/conjur_info.rb +33 -0
  23. data/lib/conjur/webserver/home.rb +36 -0
  24. data/lib/conjur/webserver/login.rb +50 -0
  25. data/lib/conjur/webserver/server.rb +111 -0
  26. data/livescript/views/audit.ls +124 -0
  27. data/public/css/bootstrap.css +7 -0
  28. data/public/css/styles.less +400 -0
  29. data/public/fonts/glyphicons-halflings-regular.eot +0 -0
  30. data/public/fonts/glyphicons-halflings-regular.svg +229 -0
  31. data/public/fonts/glyphicons-halflings-regular.ttf +0 -0
  32. data/public/fonts/glyphicons-halflings-regular.woff +0 -0
  33. data/public/images/conjur-logo.svg +26 -0
  34. data/public/images/icon-client-pc.svg +12 -0
  35. data/public/images/icon-environment.png +0 -0
  36. data/public/images/icon-person.svg +12 -0
  37. data/public/images/icon-service-dots.svg +13 -0
  38. data/public/images/icon-variable.png +0 -0
  39. data/public/index.html +121 -0
  40. data/public/js/lib/JSXTransformer.js +10862 -0
  41. data/public/js/lib/async.js +958 -0
  42. data/public/js/lib/backbone.js +2 -0
  43. data/public/js/lib/bootstrap.js +6 -0
  44. data/public/js/lib/date.extensions.js +141 -0
  45. data/public/js/lib/less.js +16 -0
  46. data/public/js/lib/moment.js +7768 -0
  47. data/public/js/lib/pace.js +2 -0
  48. data/public/js/lib/prelude-browser-min.js +1 -0
  49. data/public/js/lib/react-with-addons.js +15505 -0
  50. data/public/js/lib/react.js +14469 -0
  51. data/public/js/lib/sorted-set.no-require.js +1170 -0
  52. data/public/js/lib/sorted-set.no-require.js.txt +6 -0
  53. data/public/js/lib/underscore-min.js +6 -0
  54. data/public/js/lib/underscore.string.min.js +1 -0
  55. data/public/js/main.js +353 -0
  56. data/public/js/models/namespace.js +6 -0
  57. data/public/js/models/policyList.js +10 -0
  58. data/public/js/models/record.js +26 -0
  59. data/public/js/models/resourceList.js +61 -0
  60. data/public/js/models/userList.js +16 -0
  61. data/public/js/models/variableList.js +12 -0
  62. data/public/js/views/audit.js +191 -0
  63. data/public/js/views/dashboard.js +35 -0
  64. data/public/js/views/generic.js +42 -0
  65. data/public/js/views/group.js +32 -0
  66. data/public/js/views/groups.js +18 -0
  67. data/public/js/views/host.js +40 -0
  68. data/public/js/views/hosts.js +18 -0
  69. data/public/js/views/layer.js +63 -0
  70. data/public/js/views/layers.js +18 -0
  71. data/public/js/views/mixins/search.js +9 -0
  72. data/public/js/views/namespaces.js +40 -0
  73. data/public/js/views/navSearch.js +16 -0
  74. data/public/js/views/permissions.js +91 -0
  75. data/public/js/views/policies.js +17 -0
  76. data/public/js/views/policy.js +23 -0
  77. data/public/js/views/resource.js +23 -0
  78. data/public/js/views/role.js +18 -0
  79. data/public/js/views/searchResults.js +146 -0
  80. data/public/js/views/time.js +14 -0
  81. data/public/js/views/user.js +22 -0
  82. data/public/js/views/users.js +18 -0
  83. data/public/js/views/variable.js +41 -0
  84. data/public/js/views/variables.js +18 -0
  85. data/vendor/prelude-ls/.gitignore +2 -0
  86. data/vendor/prelude-ls/.travis.yml +3 -0
  87. data/vendor/prelude-ls/CHANGELOG.md +81 -0
  88. data/vendor/prelude-ls/LICENSE +22 -0
  89. data/vendor/prelude-ls/Makefile +50 -0
  90. data/vendor/prelude-ls/README.md +15 -0
  91. data/vendor/prelude-ls/browser/prelude-browser-min.js +1 -0
  92. data/vendor/prelude-ls/browser/prelude-browser.js +1172 -0
  93. data/vendor/prelude-ls/lib/Func.js +40 -0
  94. data/vendor/prelude-ls/lib/List.js +602 -0
  95. data/vendor/prelude-ls/lib/Num.js +129 -0
  96. data/vendor/prelude-ls/lib/Obj.js +153 -0
  97. data/vendor/prelude-ls/lib/Str.js +68 -0
  98. data/vendor/prelude-ls/lib/index.js +164 -0
  99. data/vendor/prelude-ls/package.json +50 -0
  100. data/vendor/prelude-ls/package.ls +46 -0
  101. data/vendor/prelude-ls/src/Func.ls +17 -0
  102. data/vendor/prelude-ls/src/List.ls +299 -0
  103. data/vendor/prelude-ls/src/Num.ls +83 -0
  104. data/vendor/prelude-ls/src/Obj.ls +61 -0
  105. data/vendor/prelude-ls/src/Str.ls +32 -0
  106. data/vendor/prelude-ls/src/index.ls +56 -0
  107. data/vendor/prelude-ls/test/Func.ls +36 -0
  108. data/vendor/prelude-ls/test/List.ls +751 -0
  109. data/vendor/prelude-ls/test/Num.ls +258 -0
  110. data/vendor/prelude-ls/test/Obj.ls +145 -0
  111. data/vendor/prelude-ls/test/Prelude.ls +49 -0
  112. data/vendor/prelude-ls/test/Str.ls +208 -0
  113. data/vendor/prelude-ls/test/browser.html +5 -0
  114. metadata +328 -0
@@ -0,0 +1,16 @@
1
+ if (typeof $ === "undefined") { throw new Error("jQuery is required") }
2
+
3
+ var UserListModel = function(){
4
+ var options = {
5
+ namespaceSelector: function(member) {
6
+ var idTokens = member.id.split('@');
7
+ if ( idTokens.length > 1 ) {
8
+ return idTokens.slice(1, idTokens.length-1).join['@'];
9
+ }
10
+ else {
11
+ return null;
12
+ }
13
+ }
14
+ };
15
+ return ResourceListModel("user", options);
16
+ }
@@ -0,0 +1,12 @@
1
+ if (typeof $ === "undefined") { throw new Error("jQuery is required") }
2
+
3
+ var VariableListModel = function(){
4
+ var options = {
5
+ filter: function(member) {
6
+ var idTokens = member.id.split(':');
7
+ var id = idTokens[idTokens.length-1];
8
+ return id.split('/').length > 1;
9
+ }
10
+ };
11
+ return ResourceListModel("variable", options);
12
+ }
@@ -0,0 +1,191 @@
1
+ // Generated by LiveScript 1.2.0
2
+ (function(){
3
+ var ref$, table, div, th, tr, td, thead, tbody, section, h3, time, map, each, unique, isType, join, fields, AuditTableHeader, Timestamp, wrapArray, AuditEntry, newEventSet, AuditTable, GlobalAudit, urlOfRole, urlOfResource, AuditBox, out$ = typeof exports != 'undefined' && exports || this;
4
+ ref$ = React.DOM, table = ref$.table, div = ref$.div, th = ref$.th, tr = ref$.tr, td = ref$.td, thead = ref$.thead, tbody = ref$.tbody, section = ref$.section, h3 = ref$.h3, time = ref$.time;
5
+ ref$ = require('prelude-ls'), map = ref$.map, each = ref$.each, unique = ref$.unique, isType = ref$.isType, join = ref$.join;
6
+ fields = ['timestamp', 'user', 'acting_as', 'action', 'kind', 'entity', 'privilege'];
7
+ AuditTableHeader = React.createClass({
8
+ displayName: 'AuditTableHeader',
9
+ render: function(){
10
+ return thead({}, tr({}, map(function(it){
11
+ return th({
12
+ key: it
13
+ }, it.replace('_', ' '));
14
+ })(
15
+ fields)));
16
+ }
17
+ });
18
+ Timestamp = React.createClass({
19
+ displayName: 'Timestamp',
20
+ render: function(){
21
+ var ts;
22
+ ts = moment(this.props.time);
23
+ return time({
24
+ datetime: ts.format(),
25
+ title: ts.calendar()
26
+ }, [ts.fromNow()]);
27
+ }
28
+ });
29
+ wrapArray = function(it){
30
+ if (isType('Array', it)) {
31
+ return it;
32
+ } else {
33
+ return [it];
34
+ }
35
+ };
36
+ AuditEntry = React.createClass({
37
+ displayName: 'AuditEntry',
38
+ transformedProps: function(){
39
+ var ref$;
40
+ return ref$ = clone$(this.props), ref$.entity = this.props.resource || this.props.role, ref$;
41
+ },
42
+ transformField: function(key, value){
43
+ switch (false) {
44
+ case !!value:
45
+ return value;
46
+ case key !== 'user' && key !== 'acting_as':
47
+ return RoleLink({
48
+ id: value
49
+ });
50
+ case key !== 'entity':
51
+ return ResourceLink({
52
+ data: value
53
+ });
54
+ case key !== 'timestamp':
55
+ return Timestamp({
56
+ time: value
57
+ });
58
+ default:
59
+ return value;
60
+ }
61
+ },
62
+ render: function(){
63
+ var props, this$ = this;
64
+ props = this.transformedProps();
65
+ return tr({
66
+ className: this.props.action
67
+ }, map(function(it){
68
+ return td({
69
+ key: it
70
+ }, [this$.transformField(it, props[it])]);
71
+ })(
72
+ fields));
73
+ }
74
+ });
75
+ newEventSet = function(){
76
+ var evts;
77
+ evts = new SortedSet({
78
+ comparator: function(a, b){
79
+ return a && b && b.id - a.id;
80
+ }
81
+ });
82
+ evts.containsLike = function(item){
83
+ var existing;
84
+ existing = this.findIterator(item).value();
85
+ if (existing != null) {
86
+ return this.priv.comparator(existing, item) === 0;
87
+ }
88
+ };
89
+ return evts;
90
+ };
91
+ AuditTable = React.createClass({
92
+ displayName: 'AuditTable',
93
+ getInitialState: function(){
94
+ return {
95
+ events: newEventSet()
96
+ };
97
+ },
98
+ render: function(){
99
+ return section({
100
+ className: 'audit'
101
+ }, [
102
+ h3({}, this.props.caption), table({
103
+ className: 'audit-table'
104
+ }, [
105
+ AuditTableHeader({
106
+ key: 'thead'
107
+ }), tbody({
108
+ key: 'tbody'
109
+ }, this.state.events.map(function(it){
110
+ var ref$;
111
+ return new AuditEntry((ref$ = clone$(it), ref$.key = it.id, ref$));
112
+ }))
113
+ ])
114
+ ]);
115
+ },
116
+ componentDidMount: function(){
117
+ return each(this.addSource)(
118
+ wrapArray(
119
+ this.props.src));
120
+ },
121
+ componentWillUnmount: function(){
122
+ return each(function(it){
123
+ console.log("closing event source ", it);
124
+ return it.close();
125
+ })(
126
+ this.sources);
127
+ },
128
+ addEvent: function(arg$){
129
+ var data, event;
130
+ data = arg$.data;
131
+ event = JSON.parse(data);
132
+ if (event.action === "check" && event.privilege === "read" && event.allowed) {
133
+ return true;
134
+ } else {
135
+ if (!this.state.events.containsLike(event)) {
136
+ this.state.events.insert(event);
137
+ return this.forceUpdate();
138
+ }
139
+ }
140
+ },
141
+ addSource: function(url){
142
+ var evtSrc;
143
+ console.log("opening eventsource to " + url);
144
+ evtSrc = new EventSource(url);
145
+ console.log(evtSrc);
146
+ evtSrc.onmessage = this.addEvent;
147
+ evtSrc.onerror = function(a, b, c, d){
148
+ return console.log(a, b, c, d);
149
+ };
150
+ return (this.sources || (this.sources = [])).push(evtSrc);
151
+ }
152
+ });
153
+ out$.GlobalAudit = GlobalAudit = React.createClass({
154
+ displayName: 'GlobalAudit',
155
+ render: function(){
156
+ return AuditTable({
157
+ src: '/api/audit/all',
158
+ caption: 'All recent audit events'
159
+ });
160
+ }
161
+ });
162
+ urlOfRole = function(role){
163
+ return "/api/audit/roles/" + encodeURIComponent(role);
164
+ };
165
+ urlOfResource = function(resource){
166
+ return "/api/audit/resources/" + encodeURIComponent(resource);
167
+ };
168
+ out$.AuditBox = AuditBox = React.createClass({
169
+ displayName: 'AuditBox',
170
+ render: function(){
171
+ var roles, resources, roleSrcs, resSrcs, things;
172
+ roles = this.props.roles || [];
173
+ resources = this.props.resources || [];
174
+ roleSrcs = map(urlOfRole)(
175
+ roles);
176
+ resSrcs = map(urlOfResource)(
177
+ resources);
178
+ things = join(', ')(
179
+ unique(
180
+ roles.concat(resources)));
181
+ return AuditTable({
182
+ src: roleSrcs.concat(resSrcs),
183
+ caption: "Recent audit events for " + things
184
+ });
185
+ }
186
+ });
187
+ function clone$(it){
188
+ function fun(){} fun.prototype = it;
189
+ return new fun;
190
+ }
191
+ }).call(this);
@@ -0,0 +1,35 @@
1
+ /**@jsx React.DOM*/
2
+
3
+ var DashboardSearchForm = React.createClass({
4
+ mixins: [ SearchMixin ],
5
+
6
+ render: function(){
7
+ return (
8
+ <form className="form-inline search" role="search" onSubmit={this.handleSubmit}>
9
+ <div className="form-group">
10
+ <input ref="input" type="text" className="form-control" placeholder="Search Conjur" value={this.props.searchText}>
11
+ </input>
12
+ </div>
13
+ <button type="submit" className="btn btn-default search-button">Search</button>
14
+ </form>
15
+ );
16
+ }
17
+ });
18
+
19
+ var Dashboard = React.createClass({
20
+ render: function(){
21
+ return (
22
+ <div className="dashboard">
23
+ <div className="row">
24
+ <DashboardSearchForm />
25
+ </div>
26
+ <div className="summary">
27
+ <div className="row">
28
+ </div>
29
+ <div className="row">
30
+ </div>
31
+ </div>
32
+ </div>
33
+ );
34
+ }
35
+ });
@@ -0,0 +1,42 @@
1
+ /** @jsx React.DOM */
2
+
3
+ var GenericListItem = React.createClass({
4
+ render: function() {
5
+ var recordUrl = "/ui/" + this.props.data.kind + "/" + encodeURIComponent(this.props.data.record.identifier);
6
+ return (
7
+ <tr>
8
+ <td className="id">
9
+ <a href={recordUrl}>
10
+ {this.props.data.record.identifier}
11
+ </a>
12
+ </td>
13
+ <td className="ownerId">
14
+ <RoleLink id={this.props.data.record.ownerid || this.props.data.record.owner} />
15
+ </td>
16
+ </tr>
17
+ );
18
+ }
19
+ });
20
+
21
+ var GenericList = React.createClass({
22
+ render: function() {
23
+ var rows = this.props.data.members.map(function (o) {
24
+ var componentName = _.str.capitalize(this.props.data.kind.substring(0, this.props.data.kind.length-1)) + "ListItem";
25
+ var itemKind = window[componentName] || GenericListItem;
26
+ return itemKind({data: {kind: this.props.data.kind, record: o}});
27
+ }.bind(this));
28
+ return (
29
+ <table className={this.props.data.kind + "List"}>
30
+ <thead>
31
+ <tr>
32
+ <th>Id</th>
33
+ <th>Owner</th>
34
+ </tr>
35
+ </thead>
36
+ <tbody>
37
+ {rows}
38
+ </tbody>
39
+ </table>
40
+ );
41
+ }
42
+ });
@@ -0,0 +1,32 @@
1
+ /** @jsx React.DOM */
2
+
3
+ var Group = React.createClass({
4
+ render: function() {
5
+ var members = this.props.data.members.map(function (member) {
6
+ return <li>
7
+ <RoleLink id={member.member} />
8
+ </li>
9
+ }.bind(this));
10
+ var resourceId = [ conjurConfiguration.account, 'group', this.props.data.group.id ].join(':')
11
+ var group = this.props.data.group;
12
+ return (
13
+ <div className="group">
14
+ <h2>Group {this.props.data.group.id}</h2>
15
+ <dl>
16
+ <dt>Owner</dt>
17
+ <dd><RoleLink id={this.props.data.group.ownerid}/></dd>
18
+ <dt>Members</dt>
19
+ <dd>
20
+ <ul>
21
+ {members}
22
+ </ul>
23
+ </dd>
24
+ </dl>
25
+ <Permissions role={group.roleid}/>
26
+ <div className="audit auditGroup">
27
+ <AuditBox roles={[resourceId]} resources={[resourceId]}/>
28
+ </div>
29
+ </div>
30
+ );
31
+ }
32
+ });
@@ -0,0 +1,18 @@
1
+ /** @jsx React.DOM */
2
+
3
+ var GroupBox = React.createClass({
4
+ getInitialState: function() {
5
+ return { currentNamespace: "", members: [] };
6
+ },
7
+ render: function() {
8
+ return (
9
+ <div className="groupBox">
10
+ <NamespaceFilter currentNamespace={this.state.currentNamespace} namespaces={this.props.data.namespaces} />
11
+ <div className="groupList">
12
+ <h2>Groups</h2>
13
+ <GenericList data={{kind: "groups", members: this.state.members}} />
14
+ </div>
15
+ </div>
16
+ );
17
+ }
18
+ });
@@ -0,0 +1,40 @@
1
+ /** @jsx React.DOM */
2
+
3
+ var HostLink = React.createClass({
4
+ hostId : function() {
5
+ return this.props.data.split(':')[2];
6
+ },
7
+
8
+ hostUrl: function() {
9
+ return "/ui/hosts/" + encodeURIComponent(this.hostId());
10
+ },
11
+
12
+ render: function() {
13
+ return (
14
+ <a href={this.hostUrl()}>
15
+ {this.hostId()}
16
+ </a>
17
+ );
18
+ }
19
+ });
20
+
21
+ var Host = React.createClass({
22
+ render: function(){
23
+ var host = this.props.data;
24
+ return (
25
+ <div className="host">
26
+ <h2> Host {host.id} </h2>
27
+ <dl>
28
+ <dt> Owner </dt>
29
+ <dd> <RoleLink id={host.ownerid}/> </dd>
30
+ <dt> Created At </dt>
31
+ <dd> <Time timestamp={host.created_at}/> </dd>
32
+ </dl>
33
+ <Permissions role={host.roleid}/>
34
+ <div className="audit auditHost">
35
+ <AuditBox roles={[host.roleid]} resources={[host.resource_identifier]}/>
36
+ </div>
37
+ </div>
38
+ );
39
+ }
40
+ })
@@ -0,0 +1,18 @@
1
+ /** @jsx React.DOM */
2
+
3
+ var HostBox = React.createClass({
4
+ getInitialState: function() {
5
+ return { currentNamespace: "", members: [] };
6
+ },
7
+ render: function() {
8
+ return (
9
+ <div className="hostBox">
10
+ <NamespaceFilter currentNamespace={this.state.currentNamespace} namespaces={this.props.data.namespaces} />
11
+ <div className="hostList">
12
+ <h2>Hosts</h2>
13
+ <GenericList data={{kind: "hosts", members: this.state.members}} />
14
+ </div>
15
+ </div>
16
+ );
17
+ }
18
+ });
@@ -0,0 +1,63 @@
1
+ /** @jsx React.DOM */
2
+
3
+ var Layer = React.createClass({
4
+ render: function() {
5
+ function abstractRole(expected) {
6
+ return function(role) {
7
+ var tokens = role.split(':');
8
+ var kind = tokens[1];
9
+ var abstractKinds = [ '@', 'layer' ];
10
+ var isAbstract = abstractKinds.indexOf(kind) !== -1;
11
+ return isAbstract === expected;
12
+ }
13
+ }
14
+
15
+ var layer = this.props.data.layer;
16
+
17
+
18
+ var hosts = layer.hosts.map(function (host) {
19
+ return <li>
20
+ <HostLink data={host} />
21
+ </li>
22
+ }.bind(this));
23
+ var admins = this.props.data.admins.filter(abstractRole(false)).map(function (role) {
24
+ return <RoleLink id={role}/>;
25
+ }.bind(this));
26
+ var users = this.props.data.users.filter(abstractRole(false)).map(function (role) {
27
+ return <RoleLink id={role}/>
28
+ }.bind(this));
29
+
30
+ return (
31
+ <div className="group">
32
+ <h2>Layer {layer.id}</h2>
33
+
34
+ <dl>
35
+ <dt>Owner</dt>
36
+ <dd><RoleLink id={layer.ownerid}/></dd>
37
+ <dt>Admins</dt>
38
+ <dd>
39
+ <ul>
40
+ {admins}
41
+ </ul>
42
+ </dd>
43
+ <dt>Users</dt>
44
+ <dd>
45
+ <ul>
46
+ {users}
47
+ </ul>
48
+ </dd>
49
+ <dt>Hosts</dt>
50
+ <dd>
51
+ <ul>
52
+ {hosts}
53
+ </ul>
54
+ </dd>
55
+ </dl>
56
+ <Permissions role={layer.roleid}/>
57
+ <div className="audit auditLayer">
58
+ <AuditBox roles={[layer.roleid]} resources={[layer.resource_identifier]}/>
59
+ </div>
60
+ </div>
61
+ );
62
+ }
63
+ });