Commit beb2e1c5 authored by Claudemir Todo Bom's avatar Claudemir Todo Bom

2nd factor

parent f4e666ae
......@@ -8,6 +8,8 @@ use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;
use OTPHP\TOTP;
use PWGen\PWGen;
class UsersController extends Controller
{
......@@ -22,21 +24,42 @@ class UsersController extends Controller
}
public function showOneUser($address) {
if (Gate::allows('read-user',$address))
{
$result = DB::table('users')->select('address','name','spamreject')->where('address',$address)->get();
$result = DB::table('users')->select('address','name','spamreject','totpactive')->where('address',$address)->get();
return response()->json($result);
}
return response()->json([]);
}
public function OTPStart($address) {
public function generatePassword($address) {
if (Gate::allows('set-pwd',$address))
{
$pwgen = new PWGen(6, false, true, false, true);
return response()->json($pwgen->generate());
}
return response()->json([]);
}
public function OTPStart($address, $code=NULL) {
if (Gate::allows('setup-otp',$address)) {
if (DB::table('users')->select('totpsecret')->where([ ['address',$address] , ['totpsecret','<>',''] ] )->exists()) {
if ( $code ) {
$user = DB::table('users')->select('totpsecret')->where([ ['address',$address] , ['totpactive','>',0] ] )->first();
if ( ! $user->totpsecret ) {
return response()->json([]);
};
$oldotp = new TOTP($address,$user->totpsecret);
if (!$oldotp->verify($code)) {
return response()->json([]);
}
}
if ( !$code && DB::table('users')->select('totpsecret')->where([ ['address',$address] , ['totpactive','>',0] ] )->exists()) {
return response()->json([]);
};
$otp = new TOTP($address);
$otp->setIssuer("ww-mail");
$parameters = $otp->getParameters();
......@@ -66,7 +89,6 @@ class UsersController extends Controller
return response()->json([$result]);
}
return response()->json([]);
}
}
......@@ -41,6 +41,22 @@ class BasicWebAuth
*/
public function handle($request, Closure $next)
{
$headers = [
'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Methods' => 'POST, GET, OPTIONS, PUT, DELETE',
'Access-Control-Allow-Credentials' => 'true',
'Access-Control-Max-Age' => '86400',
'Access-Control-Allow-Headers' => 'Content-Type, Authorization, X-Requested-With'
];
error_log("handling ".$request->getMethod());
if ($request->isMethod('OPTIONS'))
{
return response()->json('{"method":"OPTIONS"}', 200, $headers);
}
if ( false === $request->header('PHP_AUTH_USER', false) )
{
return $this->notAuthorisedResponse();
......@@ -52,16 +68,24 @@ class BasicWebAuth
}
}
return $next($request);
$response = $next($request);
foreach($headers as $key => $value)
{
$response->header($key, $value);
}
return $response;
}
private function notAuthorisedResponse()
{
/** @var Response $response */
$response = new Response();
$response->header('WWW-Authenticate', 'Basic realm="'. $this->realm .'"');
// do not advertise http basic auth to avoid browser popup dialog
// $response->header('WWW-Authenticate', 'Basic realm="'. $this->realm .'"');
$response->setStatusCode(401);
$response->setContent('401: You are not authorised');
$response->setContent('401: HTTP Basic Auth failed');
return $response;
}
}
......@@ -8,7 +8,8 @@
"php": ">=5.6.4",
"laravel/lumen-framework": "5.5.*",
"vlucas/phpdotenv": "~2.2",
"spomky-labs/otphp": "^8.3"
"spomky-labs/otphp": "^8.3",
"roderik/pwgen-php": "^0.1.8"
},
"require-dev": {
"fzaninotto/faker": "~1.4",
......
......@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "423052c178a76cbd8cbdbbf1f63c1fb2",
"content-hash": "68e6bacb9675f16c4b200d59a522a9e5",
"packages": [
{
"name": "beberlei/assert",
......@@ -1743,6 +1743,53 @@
],
"time": "2017-10-23T01:57:42+00:00"
},
{
"name": "roderik/pwgen-php",
"version": "0.1.8",
"source": {
"type": "git",
"url": "https://github.com/roderik/pwgen-php.git",
"reference": "19763b860eeb94b818cfc67fd6a47b697594e1da"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/roderik/pwgen-php/zipball/19763b860eeb94b818cfc67fd6a47b697594e1da",
"reference": "19763b860eeb94b818cfc67fd6a47b697594e1da",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "^6.4"
},
"type": "library",
"autoload": {
"psr-4": {
"PWGen\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"GPL"
],
"authors": [
{
"name": "Theodore Ts'o",
"email": "tytso@alum.mit.edu"
},
{
"name": "Superwayne",
"email": "superwayne@superwayne.org"
}
],
"description": "pwgen-php is a simple PHP class which aims to clone the GNU pwgen functionality.",
"keywords": [
"generator",
"password"
],
"time": "2017-12-01T08:47:54+00:00"
},
{
"name": "spomky-labs/otphp",
"version": "v8.3.2",
......
......@@ -20,6 +20,8 @@ $router->group(['prefix' => 'api'], function () use ($router) {
$router->get('otp/start/{address:[0-9A-Za-z_.@]+}', [ 'middleware' => 'basic.auth' , 'uses' => 'UsersController@OTPStart']);
$router->get('otp/start/{address:[0-9A-Za-z_.@]+}/{code:[0-9]{6}}', [ 'middleware' => 'basic.auth' , 'uses' => 'UsersController@OTPStart']);
$router->get('otp/confirm/{address:[0-9A-Za-z_.@]+}/{code:[0-9]{6}}', [ 'middleware' => 'basic.auth' , 'uses' => 'UsersController@OTPConfirm']);
$router->get('test', ['uses' => 'UsersController@test']);
......
node_modules
build
#!/bin/bash
./node_modules/.bin/webpack --config webpack.config.js --watch
QR=require('qrcode-generator-es6').default;
function make_base_auth(user, password) {
var tok = user + ':' + password;
var hash = btoa(tok);
return "Basic " + hash;
}
function activateBox(name) {
$(".contentbox").hide();
$(name).show();
}
function message(text) {
$('#messagetext').html(text);
activateBox('#message');
}
function messageOk(text) {
message(text);
}
function messageError(text) {
message(text);
}
function otpStart(loginfield, pwdfield, otpcode) {
otpcode = otpcode || 0;
$.ajax
({
type: "GET",
url: "http://localhost/wwmail/index.php/api/otp/start/"+loginfield+(otpcode?("/"+otpcode):""),
beforeSend: function (xhr){
xhr.setRequestHeader('Authorization', make_base_auth(loginfield, pwdfield));
},
success: function (data){
myel = document.getElementById("qrcode");
const qrcode = new QR(0, 'H');
qrcode.addData(data.uri);
qrcode.make();
myel.innerHTML = qrcode.createSvgTag({});
$('#qrcodelink').attr('href',data.uri);
$("button#setupotp").click( function() {
otpcode = $("#otpcode").val();
otpConfirm(loginfield,pwdfield,otpcode);
})
activateBox('#otpqr');
},
error: function () {
messageError("Não deu certo!");
}
});
}
function otpConfirm(loginfield, pwdfield, otpcode) {
$.ajax
({
type: "GET",
url: "http://localhost/wwmail/index.php/api/otp/confirm/"+loginfield+"/"+otpcode,
beforeSend: function (xhr){
xhr.setRequestHeader('Authorization', make_base_auth(loginfield, pwdfield));
},
success: function (data){
messageOk("Segundo fator configurado com sucesso!");
},
error: function () {
messageError("Não deu certo!");
}
});
}
$(document).ready( function() {
$(".title").each( function (e) { $(this).html("Configuração de Segundo Fator") });
$("button#reload").click( function() {
location.reload();
});
$("form#login").submit( function(form) {
form.preventDefault();
loginfield = $("#loginfield").val();
pwdfield = $("#pwdfield").val();
$.ajax
({
type: "GET",
url: "http://localhost/wwmail/index.php/api/user/"+loginfield,
beforeSend: function (xhr){
xhr.setRequestHeader('Authorization', make_base_auth(loginfield, pwdfield));
},
success: function (data){
if (data[0].totpactive) {
$('button#b-reset').click( function() {
otpresetcode = $("#otpresetcode").val();
otpStart(loginfield, pwdfield, otpresetcode);
})
activateBox("#otpreset");
} else {
otpStart(loginfield, pwdfield);
}
},
error: function () {
messageError("Não deu certo!");
}
});
});
activateBox('#loginform');
});
{
"name": "wwmail-ui",
"version": "0.0.1",
"description": "WW Mail Web User Interface",
"main": "js/wwmail-ui.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Claudemir Todo Bom",
"license": "GPL-2.0",
"dependencies": {
"jquery": "^3.3.1",
"qrcode-generator-es6": "^1.1.3",
"webpack": "^4.10.2"
},
"devDependencies": {
"webpack-cli": "^3.0.1"
}
}
<html>
<head>
<title class="title"></title>
<meta charset="utf-8">
<meta name='viewport' content='width=device-width, user-scalable=no'>
<link rel='stylesheet' type='text/css' href='wwmail.css'>
</head>
<body>
<div id='main'>
<h1 class="title"></h1>
<div id='loginform' class='contentbox'>
<form id='login'>
<label>E-mail:</label><input id='loginfield' type='text' name='login'><br>
<label>Senha:</label><input id='pwdfield' type='password' name='password'><br>
<button type='submit'>Login</button>
</form>
</div>
<div id='otpqr' class='contentbox'>
<a id="qrcodelink"><div id="qrcode"></div></a>
<label>Código:</label>
<input id='otpcode' type='text' name='otpcode'><br>
<button id='setupotp'>Setup</button>
</div>
<div id='otpreset' class='contentbox'>
<p>O segundo fator já está configurado, se desejar alterá-lo,
preencha abaixo com código atual.</p>
<label>Código:</label><input id='otpresetcode' type='text' name='otpcode'><br>
<button id='b-reset'>Resetar</button>
</div>
<div id='message' class='contentbox'>
<div id='messagetext'></div>
<button id='reload'>OK</button>
</div>
</div>
<script type="text/javascript" src="build/wwmailui-webpack.js"></script>
</body>
</html>
var webpack = require('webpack');
module.exports = {
mode: "development",
devtool: "inline-source-map",
context: __dirname,
entry: {
wwmailui: "./js/wwmail-ui.js"
},
resolve: {
alias: {
'handlebars' : 'handlebars/dist/handlebars.js'
}
},
node: {
fs: "empty"
},
output: {
path: __dirname + "/build/",
filename: "[name]-webpack.js"
},
module: {
rules: [
{
test: /\.(png|woff|woff2|eot|ttf|svg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 100000
}
}
]
},
{
test: /\.less$/,
use: [
{
loader: "style-loader"
}
]
}
]
},
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
})
]
// plugins: [
// new webpack.optimize.UglifyJsPlugin({
// compress: {
// warnings: false
// }
// })
// ]
}
......@@ -26,3 +26,7 @@ button {
color: white;
background-color: blue;
}
#loginform, #otpqr, #message {
display: none;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment