Land #11142, use POST for API token generation
commit
d117e6a1d1
|
@ -15,26 +15,21 @@ module AuthApiDoc
|
||||||
end
|
end
|
||||||
|
|
||||||
swagger_path '/api/v1/auth/generate-token' do
|
swagger_path '/api/v1/auth/generate-token' do
|
||||||
# Swagger documentation for /api/v1/auth/generate-token GET
|
# Swagger documentation for /api/v1/auth/generate-token POST
|
||||||
operation :get do
|
operation :post do
|
||||||
|
|
||||||
key :description, 'Return a valid Authorization Bearer token.'
|
key :description, 'Return a valid Authorization Bearer token.'
|
||||||
key :tags, [ 'auth' ]
|
key :tags, [ 'auth' ]
|
||||||
|
|
||||||
parameter do
|
parameter do
|
||||||
key :name, :username
|
key :in, :body
|
||||||
key :in, :query
|
key :name, :body
|
||||||
key :description, 'The username for the user you want to authenticate.'
|
key :description, 'Login credentials for the user who will be generating a token.'
|
||||||
key :required, true
|
key :required, true
|
||||||
key :type, :string
|
schema do
|
||||||
|
property :username, type: :string, required: true
|
||||||
|
property :password, type: :string, required: true
|
||||||
end
|
end
|
||||||
|
|
||||||
parameter do
|
|
||||||
key :name, :password
|
|
||||||
key :in, :query
|
|
||||||
key :description, 'The password for the user you want to authenticate.'
|
|
||||||
key :required, true
|
|
||||||
key :type, :string
|
|
||||||
end
|
end
|
||||||
|
|
||||||
response 200 do
|
response 200 do
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
require 'json'
|
||||||
|
|
||||||
module Authentication
|
module Authentication
|
||||||
module Strategies
|
module Strategies
|
||||||
class UserPassword < Warden::Strategies::Base
|
class UserPassword < Warden::Strategies::Base
|
||||||
|
@ -16,21 +18,31 @@ module Authentication
|
||||||
# Check if request contains valid data and should be authenticated.
|
# Check if request contains valid data and should be authenticated.
|
||||||
# @return [Boolean] true if strategy should be run for the request; otherwise, false.
|
# @return [Boolean] true if strategy should be run for the request; otherwise, false.
|
||||||
def valid?
|
def valid?
|
||||||
params['username'] && params['password']
|
begin
|
||||||
|
body = JSON.parse(request.body.read, symbolize_names: true)
|
||||||
|
body[:username] && body[:password]
|
||||||
|
ensure
|
||||||
|
request.body.rewind # Reset the StringIO buffer so any further consumers can read the body
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Authenticate the request.
|
# Authenticate the request.
|
||||||
def authenticate!
|
def authenticate!
|
||||||
db_manager = env['msf.db_manager']
|
begin
|
||||||
user = db_manager.users(username: params['username']).first
|
body = JSON.parse(request.body.read, symbolize_names: true)
|
||||||
|
|
||||||
if user.nil? || !db_manager.authenticate_user(id: user.id, password: params['password'])
|
db_manager = env['msf.db_manager']
|
||||||
|
user = db_manager.users(username: body[:username]).first
|
||||||
|
|
||||||
|
if user.nil? || !db_manager.authenticate_user(id: user.id, password: body[:password])
|
||||||
fail("Invalid username or password.")
|
fail("Invalid username or password.")
|
||||||
else
|
else
|
||||||
success!(user)
|
success!(user)
|
||||||
end
|
end
|
||||||
|
ensure
|
||||||
|
request.body.rewind # Reset the StringIO buffer so any further consumers can read the body
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -86,7 +86,7 @@ input[type=text], input[type=password] {
|
||||||
height: 34px;
|
height: 34px;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
input[type=button] {
|
||||||
border-color: rgba(0, 0, 0, 0.6);
|
border-color: rgba(0, 0, 0, 0.6);
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
|
@ -31,7 +31,7 @@ module AuthServlet
|
||||||
app.post AuthServlet.api_login_path, &post_login
|
app.post AuthServlet.api_login_path, &post_login
|
||||||
|
|
||||||
app.get AuthServlet.api_logout_path, &get_logout
|
app.get AuthServlet.api_logout_path, &get_logout
|
||||||
app.get AuthServlet.api_generate_token_path, &get_generate_token
|
app.post AuthServlet.api_generate_token_path, &post_generate_token
|
||||||
app.post "#{AuthServlet.api_unauthenticated_path}/?:scope?", &post_unauthenticated
|
app.post "#{AuthServlet.api_unauthenticated_path}/?:scope?", &post_unauthenticated
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ module AuthServlet
|
||||||
end
|
end
|
||||||
|
|
||||||
# Generate a new API token for the current user
|
# Generate a new API token for the current user
|
||||||
def self.get_generate_token
|
def self.post_generate_token
|
||||||
lambda {
|
lambda {
|
||||||
# change action to drop the scope param since this is used
|
# change action to drop the scope param since this is used
|
||||||
# by XMLHttpRequest (XHR) and we don't want a redirect
|
# by XMLHttpRequest (XHR) and we don't want a redirect
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
function getNewApiToken() {
|
function getNewApiToken() {
|
||||||
loadDoc("GET", "<%= AuthServlet.api_generate_token_path %>", function(xhr) {
|
loadDoc("POST", "<%= AuthServlet.api_generate_token_path %>", function(xhr) {
|
||||||
var response = JSON.parse(xhr.responseText);
|
var response = JSON.parse(xhr.responseText);
|
||||||
document.getElementById("api-token").innerHTML = response.data.token;
|
document.getElementById("api-token").innerHTML = response.data.token;
|
||||||
}, errorHandler);
|
}, errorHandler);
|
||||||
|
@ -61,6 +61,8 @@
|
||||||
<div id="api-token" class="api-token">
|
<div id="api-token" class="api-token">
|
||||||
<%= !warden.user(:user).nil? && !warden.user(:user).persistence_token.nil? ? warden.user(:user).persistence_token : 'none' %>
|
<%= !warden.user(:user).nil? && !warden.user(:user).persistence_token.nil? ? warden.user(:user).persistence_token : 'none' %>
|
||||||
</div>
|
</div>
|
||||||
|
<% else %>
|
||||||
|
<div id="not-logged-in-label">You are not currently logged in. Please click <a href="<%= AuthServlet.api_login_path %>">here</a> to be taken to the login page.</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,49 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
<script
|
||||||
|
src="https://code.jquery.com/jquery-3.3.1.min.js"
|
||||||
|
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
<script>
|
||||||
|
function ConvertFormToJSON(form){
|
||||||
|
var array = jQuery(form).serializeArray();
|
||||||
|
var json = {};
|
||||||
|
|
||||||
|
jQuery.each(array, function() {
|
||||||
|
json[this.name] = this.value || '';
|
||||||
|
});
|
||||||
|
|
||||||
|
return JSON.stringify(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function(){
|
||||||
|
$("#submit").on('click', function(){
|
||||||
|
$.ajax({
|
||||||
|
url: '<%= AuthServlet.api_login_path %>',
|
||||||
|
type : "POST",
|
||||||
|
data : ConvertFormToJSON($("#login_form")),
|
||||||
|
contentType: "application/json; charset=utf-8",
|
||||||
|
processData: false,
|
||||||
|
success : function(data) {
|
||||||
|
// TODO: This currently always redirects the user to the /auth/account page.
|
||||||
|
// This is because the POST /login endpoint always returns a redirect, which
|
||||||
|
// is not easily handled by Javascript AJAX requests. When the /login endpoint
|
||||||
|
// is more fully fleshed out we should add proper handling for valid and
|
||||||
|
// invalid login attempts.
|
||||||
|
window.location.replace('<%= AuthServlet.api_account_path %>');
|
||||||
|
},
|
||||||
|
error: function(xhr, resp, text) {
|
||||||
|
console.log(xhr, resp, text);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
<div style="padding:20px;">
|
<div style="padding:20px;">
|
||||||
<form action="<%= AuthServlet.api_login_path %>" method="post">
|
<form id="login_form" action="" method="post">
|
||||||
<div class="credential-container">
|
<div class="credential-container">
|
||||||
<h2>Log In - Metasploit API</h2>
|
<h2>Log In - Metasploit API</h2>
|
||||||
<label for="username"><b>Username</b></label>
|
<label for="username"><b>Username</b></label>
|
||||||
|
@ -16,8 +57,7 @@
|
||||||
|
|
||||||
<label for="password"><b>Password</b></label>
|
<label for="password"><b>Password</b></label>
|
||||||
<input type="password" placeholder="Enter Password" name="password" required>
|
<input type="password" placeholder="Enter Password" name="password" required>
|
||||||
|
<input id="submit" type="button" name="submit" value="submit">
|
||||||
<button type="submit">Log In</button>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
2
msfdb
2
msfdb
|
@ -636,7 +636,7 @@ def add_web_service_user
|
||||||
|
|
||||||
# Send request to create new API token for the user
|
# Send request to create new API token for the user
|
||||||
generate_token_uri = get_web_service_uri(path: '/api/v1/auth/generate-token')
|
generate_token_uri = get_web_service_uri(path: '/api/v1/auth/generate-token')
|
||||||
response_data = http_request(uri: generate_token_uri, query: cred_data, method: :get,
|
response_data = http_request(uri: generate_token_uri, data: cred_data, method: :post,
|
||||||
skip_verify: skip_ssl_verify?, cert: get_ssl_cert)
|
skip_verify: skip_ssl_verify?, cert: get_ssl_cert)
|
||||||
response = response_data[:response]
|
response = response_data[:response]
|
||||||
puts "add_web_service_user: generate token response=#{response}" if @options[:debug]
|
puts "add_web_service_user: generate token response=#{response}" if @options[:debug]
|
||||||
|
|
Loading…
Reference in New Issue