Skip to content

Commit

Permalink
Fixes #38108 - As a user I want to invalidate tokens for self(UI)
Browse files Browse the repository at this point in the history
  • Loading branch information
girijaasoni committed Dec 26, 2024
1 parent bc2dbbf commit bed624f
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 10 deletions.
13 changes: 10 additions & 3 deletions app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,16 @@ def impersonate
def invalidate_jwt
@user = find_resource(:edit_users)
@user.jwt_secret&.destroy
process_success(
:success_msg => _('Successfully invalidated JWTs for %s.') % @user.login
)
respond_to do |format|
format.html do
process_success(
:success_msg => _('Successfully invalidated registration tokens for %s.') % @user.login
)
end
format.json do
render :json => {}, :status => :ok
end
end
end

def stop_impersonation
Expand Down
2 changes: 1 addition & 1 deletion app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ def can_change_admin_flag?

def editing_self?(options = {})
options[:controller].to_s == 'users' &&
options[:action] =~ /edit|update/ &&
options[:action] =~ /edit|update|invalidate_jwt/ &&
options[:id].to_i == id ||
options[:controller].to_s =~ /\Aapi\/v\d+\/users\Z/ &&
options[:action] =~ /show|update/ &&
Expand Down
5 changes: 5 additions & 0 deletions app/views/jwt_tokens/_jwt_tokens_tab.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div class="tab-pane" id="jwt_tokens">
<%= react_component('JwtTokens', {
userId: @user.id,
}) %>
</div>
7 changes: 7 additions & 0 deletions app/views/users/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
<% if @editing_self || (@user.persisted? && authorized_for(hash_for_api_user_personal_access_tokens_path(user_id: @user))) %>
<li><a href='#personal_access_tokens' data-toggle='tab'><%= _('Personal Access Tokens') %></a></li>
<% end %>
<% if @editing_self %>
<li><a href='#jwt_tokens' data-toggle='tab'><%= _('Registration Tokens') %></a></li>
<% end %>
<%= render_tab_header_for(:main_tabs, :subject => @user, :form => f) %>
</ul>

Expand Down Expand Up @@ -97,6 +100,10 @@
<%= render 'personal_access_tokens/personal_access_tokens_tab', :f => f, :user => @user %>
<% end %>

<% if @editing_self %>
<%= render 'jwt_tokens/jwt_tokens_tab', :f => f, :user => @user %>
<% end %>

<div class='tab-pane' id='roles'>
<% caption = @user.inherited_admin? ? _('Admin rights are currently inherited from a user group') : '' %>
<%= checkbox_f f, :admin, help_block: caption if User.current.can_change_admin_flag? %>
Expand Down
25 changes: 19 additions & 6 deletions test/controllers/users_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -162,26 +162,39 @@ class UsersControllerTest < ActionController::TestCase
User.current = users(:admin)
user = users(:two)
FactoryBot.build(:jwt_secret, token: 'test_jwt_secret', user: user)
patch :invalidate_jwt, params: { :id => user.id }
patch :invalidate_jwt, params: { :id => user.id }, session: set_session_user(User.current)
user.reload
assert_nil user.jwt_secret
assert_response :redirect
end

test "User should be able to invalidate jwt for self" do
User.current = users(:one)
user = User.current
FactoryBot.create(:jwt_secret, token: 'test_jwt_secret', user: user)
patch :invalidate_jwt, params: { :id => user.id }, session: set_session_user(User.current)
user.reload
assert_nil user.jwt_secret
assert_response :redirect
end

test 'user with edit users permission should be able to invalidate jwt for another user' do
User.current = setup_user "edit", "users"
user = users(:two)
FactoryBot.build(:jwt_secret, token: 'test_jwt_secret', user: user)
patch :invalidate_jwt, params: { :id => user.id }
user = users(:scoped)
FactoryBot.create(:jwt_secret, token: 'test_jwt_secret', user: user)
patch :invalidate_jwt, params: { :id => user.id }, session: set_session_user(User.current)
user.reload
assert_nil user.jwt_secret
assert_response :redirect
end

test 'user without edit users permission should not be able to invalidate jwt for another user' do
User.current = users(:one)
user = users(:two)
FactoryBot.build(:jwt_secret, token: 'test_jwt_secret', user: user)
patch :invalidate_jwt, params: { :id => user.id }
FactoryBot.create(:jwt_secret, token: 'test_jwt_secret', user: user)
patch :invalidate_jwt, params: { :id => user.id }, session: set_session_user(User.current)
assert_response :forbidden
assert_not_nil user.jwt_secret
end

test "should modify session when locale is updated" do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import LabelIcon from './common/LabelIcon';
import { WelcomeAuthSource } from './AuthSource/Welcome';
import { WelcomeConfigReports } from './ConfigReports/Welcome';
import { WelcomeArchitecture } from './Architectures/Welcome';
import JwtTokens from './users/JwtTokens/JwtTokens';

const componentRegistry = {
registry: forceSingleton('component_registry', () => ({})),
Expand Down Expand Up @@ -142,6 +143,7 @@ const coreComponents = [
{ name: 'SettingsTable', type: SettingsTable },
{ name: 'SettingUpdateModal', type: SettingUpdateModal },
{ name: 'PersonalAccessTokens', type: PersonalAccessTokens },
{ name: 'JwtTokens', type: JwtTokens },
{ name: 'ClipboardCopy', type: ClipboardCopy },
{ name: 'LabelIcon', type: LabelIcon },
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React, { Fragment } from 'react';
import { Button } from '@patternfly/react-core';
import { KeyIcon } from '@patternfly/react-icons';
import { useDispatch } from 'react-redux';
import PropTypes from 'prop-types';
import { openConfirmModal } from '../../ConfirmModal';
import { APIActions } from '../../../redux/API';
import { translate as __ } from '../../../common/I18n';

const JwtTokens = ({ userId }) => {
const dispatch = useDispatch();
return (
<Fragment>
<table className="table table-bordered table-striped table-hover table-fixed">
<tbody>
<tr>
<td className="blank-slate-pf">
<div className="blank-slate-pf-icon">
<KeyIcon type="fa" name="key" color="#9c9c9c" />
</div>
<h1>{__('JWT Tokens')}</h1>
<p>
{__(
'By invalidating your JSON Web Tokens (JWTs), you will no longer be able to register hosts by using your existing JWTs.'
)}
</p>
<Button
ouiaId="invalidate-jwt-token-button"
variant="primary"
isSmall
onClick={() =>
dispatch(
openConfirmModal({
isWarning: true,
title: __('Invalidate tokens for self?'),
confirmButtonText: __('Confirm'),
onConfirm: () =>
dispatch(
APIActions.patch({
url: `/users/${userId}/invalidate_jwt`,
key: `INVALIDATE-JWT`,
successToast: () =>
__(
'Successfully Invalidated registration tokens.'
),
errorToast: () => __('Unexpected error occurred.'),
})
),
})
)
}
>
{__('Invalidate JWTs')}
</Button>
</td>
</tr>
</tbody>
</table>
</Fragment>
);
};

JwtTokens.propTypes = {
userId: PropTypes.string.isRequired,
};

export default JwtTokens;

0 comments on commit bed624f

Please sign in to comment.