##// END OF EJS Templates
auth-tokens: extended views to allowed override of adding scope in EE edition.
marcink -
r1507:a630e423 default
parent child Browse files
Show More
@@ -1,111 +1,120 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import logging
22 22
23 23 from pyramid.httpexceptions import HTTPFound
24 24 from pyramid.view import view_config
25 25
26 26 from rhodecode.apps._base import BaseAppView
27 27 from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired
28 28 from rhodecode.lib.utils2 import safe_int
29 29 from rhodecode.lib import helpers as h
30 30 from rhodecode.model.auth_token import AuthTokenModel
31 31 from rhodecode.model.meta import Session
32 32
33 33 log = logging.getLogger(__name__)
34 34
35 35
36 36 class MyAccountView(BaseAppView):
37 ALLOW_SCOPED_TOKENS = False
38 """
39 This view has alternative version inside EE, if modified please take a look
40 in there as well.
41 """
37 42
38 43 def load_default_context(self):
39 44 c = self._get_local_tmpl_context()
40 45
41 46 c.auth_user = self.request.user
42 47 c.user = c.auth_user.get_instance()
43
48 c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS
44 49 self._register_global_c(c)
45 50 return c
46 51
47 52 @LoginRequired()
48 53 @NotAnonymous()
49 54 @view_config(
50 55 route_name='my_account_auth_tokens', request_method='GET',
51 56 renderer='rhodecode:templates/admin/my_account/my_account.mako')
52 57 def my_account_auth_tokens(self):
53 58 _ = self.request.translate
54 59
55 60 c = self.load_default_context()
56 61 c.active = 'auth_tokens'
57 62
58 show_expired = True
59
60 63 c.lifetime_values = [
61 64 (str(-1), _('forever')),
62 65 (str(5), _('5 minutes')),
63 66 (str(60), _('1 hour')),
64 67 (str(60 * 24), _('1 day')),
65 68 (str(60 * 24 * 30), _('1 month')),
66 69 ]
67 70 c.lifetime_options = [(c.lifetime_values, _("Lifetime"))]
68 71 c.role_values = [
69 72 (x, AuthTokenModel.cls._get_role_name(x))
70 73 for x in AuthTokenModel.cls.ROLES]
71 74 c.role_options = [(c.role_values, _("Role"))]
72 75 c.user_auth_tokens = AuthTokenModel().get_auth_tokens(
73 c.user.user_id, show_expired=show_expired)
76 c.user.user_id, show_expired=True)
74 77 return self._get_template_context(c)
75 78
79 def maybe_attach_token_scope(self, token):
80 # implemented in EE edition
81 pass
82
76 83 @LoginRequired()
77 84 @NotAnonymous()
78 85 @CSRFRequired()
79 86 @view_config(
80 87 route_name='my_account_auth_tokens_add', request_method='POST')
81 88 def my_account_auth_tokens_add(self):
82 89 _ = self.request.translate
83 90 c = self.load_default_context()
84 91
85 92 lifetime = safe_int(self.request.POST.get('lifetime'), -1)
86 93 description = self.request.POST.get('description')
87 94 role = self.request.POST.get('role')
88 95
89 AuthTokenModel().create(c.user.user_id, description, lifetime, role)
96 token = AuthTokenModel().create(
97 c.user.user_id, description, lifetime, role)
98 self.maybe_attach_token_scope(token)
90 99 Session().commit()
100
91 101 h.flash(_("Auth token successfully created"), category='success')
92
93 102 return HTTPFound(h.route_path('my_account_auth_tokens'))
94 103
95 104 @LoginRequired()
96 105 @NotAnonymous()
97 106 @CSRFRequired()
98 107 @view_config(
99 108 route_name='my_account_auth_tokens_delete', request_method='POST')
100 109 def my_account_auth_tokens_delete(self):
101 110 _ = self.request.translate
102 111 c = self.load_default_context()
103 112
104 113 del_auth_token = self.request.POST.get('del_auth_token')
105 114
106 115 if del_auth_token:
107 116 AuthTokenModel().delete(del_auth_token, c.user.user_id)
108 117 Session().commit()
109 118 h.flash(_("Auth token successfully deleted"), category='success')
110 119
111 120 return HTTPFound(h.route_path('my_account_auth_tokens'))
@@ -1,95 +1,158 b''
1 1 <div class="panel panel-default">
2 2 <div class="panel-heading">
3 3 <h3 class="panel-title">${_('Authentication Tokens')}</h3>
4 4 </div>
5 5 <div class="panel-body">
6 6 <p>
7 7 ${_('Each token can have a role. Token with a role can be used only in given context, '
8 8 'e.g. VCS tokens can be used together with the authtoken auth plugin for git/hg/svn operations only.')}
9 ${_('Additionally scope for VCS type token can narrow the use to chosen repository.')}
10 9 </p>
11 10 <table class="rctable auth_tokens">
12 11 %if c.user_auth_tokens:
13 12 <tr>
14 13 <th>${_('Token')}</th>
15 14 <th>${_('Scope')}</th>
16 15 <th>${_('Description')}</th>
17 16 <th>${_('Role')}</th>
18 17 <th>${_('Expiration')}</th>
19 18 <th>${_('Action')}</th>
20 19 </tr>
21 20 %for auth_token in c.user_auth_tokens:
22 21 <tr class="${'expired' if auth_token.expired else ''}">
23 22 <td class="truncate-wrap td-authtoken">
24 23 <div class="user_auth_tokens truncate autoexpand">
25 24 <code>${auth_token.api_key}</code>
26 25 </div>
27 26 </td>
28 27 <td class="td">${auth_token.scope_humanized}</td>
29 28 <td class="td-wrap">${auth_token.description}</td>
30 29 <td class="td-tags">
31 30 <span class="tag disabled">${auth_token.role_humanized}</span>
32 31 </td>
33 32 <td class="td-exp">
34 33 %if auth_token.expires == -1:
35 34 ${_('never')}
36 35 %else:
37 36 %if auth_token.expired:
38 37 <span style="text-decoration: line-through">${h.age_component(h.time_to_utcdatetime(auth_token.expires))}</span>
39 38 %else:
40 39 ${h.age_component(h.time_to_utcdatetime(auth_token.expires))}
41 40 %endif
42 41 %endif
43 42 </td>
44 43 <td class="td-action">
45 44 ${h.secure_form(h.route_path('my_account_auth_tokens_delete'), method='post')}
46 45 ${h.hidden('del_auth_token',auth_token.api_key)}
47 46 <button class="btn btn-link btn-danger" type="submit"
48 47 onclick="return confirm('${_('Confirm to remove this auth token: %s') % auth_token.api_key}');">
49 48 ${_('Delete')}
50 49 </button>
51 50 ${h.end_form()}
52 51 </td>
53 52 </tr>
54 53 %endfor
55 54 %else:
56 55 <tr><td><div class="ip">${_('No additional auth token specified')}</div></td></tr>
57 56 %endif
58 57 </table>
59 58
60 59 <div class="user_auth_tokens">
61 60 ${h.secure_form(h.route_path('my_account_auth_tokens_add'), method='post')}
62 61 <div class="form form-vertical">
63 62 <!-- fields -->
64 63 <div class="fields">
65 64 <div class="field">
66 65 <div class="label">
67 66 <label for="new_email">${_('New authentication token')}:</label>
68 67 </div>
69 68 <div class="input">
70 69 ${h.text('description', placeholder=_('Description'))}
71 70 ${h.select('lifetime', '', c.lifetime_options)}
72 71 ${h.select('role', '', c.role_options)}
72
73 % if c.allow_scoped_tokens:
74 ${h.hidden('scope_repo_id')}
75 % else:
76 ${h.select('scope_repo_id_disabled', '', ['Scopes available in EE edition'], disabled='disabled')}
77 % endif
73 78 </div>
79 <p class="help-block">
80 ${_('Repository scope works only with tokens with VCS type.')}
81 </p>
74 82 </div>
75 83 <div class="buttons">
76 84 ${h.submit('save',_('Add'),class_="btn")}
77 85 ${h.reset('reset',_('Reset'),class_="btn")}
78 86 </div>
79 87 </div>
80 88 </div>
81 89 ${h.end_form()}
82 90 </div>
83 91 </div>
84 92 </div>
85 <script>
86 $(document).ready(function(){
87 var select2Options = {
88 'containerCssClass': "drop-menu",
89 'dropdownCssClass': "drop-menu-dropdown",
90 'dropdownAutoWidth': true
91 };
92 $("#lifetime").select2(select2Options);
93 $("#role").select2(select2Options);
94 });
95 </script>
93 <script>
94 $(document).ready(function(){
95
96 var select2Options = {
97 'containerCssClass': "drop-menu",
98 'dropdownCssClass': "drop-menu-dropdown",
99 'dropdownAutoWidth': true
100 };
101 $("#lifetime").select2(select2Options);
102 $("#role").select2(select2Options);
103
104 var repoFilter = function(data) {
105 var results = [];
106
107 if (!data.results[0]) {
108 return data
109 }
110
111 $.each(data.results[0].children, function() {
112 // replace name to ID for submision
113 this.id = this.obj.repo_id;
114 results.push(this);
115 });
116
117 data.results[0].children = results;
118 return data;
119 };
120
121 $("#scope_repo_id_disabled").select2(select2Options);
122
123 $("#scope_repo_id").select2({
124 cachedDataSource: {},
125 minimumInputLength: 2,
126 placeholder: "${_('repository scope')}",
127 dropdownAutoWidth: true,
128 containerCssClass: "drop-menu",
129 dropdownCssClass: "drop-menu-dropdown",
130 formatResult: formatResult,
131 query: $.debounce(250, function(query){
132 self = this;
133 var cacheKey = query.term;
134 var cachedData = self.cachedDataSource[cacheKey];
135
136 if (cachedData) {
137 query.callback({results: cachedData.results});
138 } else {
139 $.ajax({
140 url: "${h.url('repo_list_data')}",
141 data: {'query': query.term},
142 dataType: 'json',
143 type: 'GET',
144 success: function(data) {
145 data = repoFilter(data);
146 self.cachedDataSource[cacheKey] = data;
147 query.callback({results: data.results});
148 },
149 error: function(data, textStatus, errorThrown) {
150 alert("Error while fetching entries.\nError code {0} ({1}).".format(data.status, data.statusText));
151 }
152 })
153 }
154 })
155 });
156
157 });
158 </script>
General Comments 0
You need to be logged in to leave comments. Login now