Commit b4a33dce by aagusti

perbaikan user login dan csrf

1 parent be1cb753
...@@ -197,8 +197,30 @@ Tambahkan blok berikut ini dibawah ini file ...@@ -197,8 +197,30 @@ Tambahkan blok berikut ini dibawah ini file
proxy_set_header X-Forwarded-Host $host:$server_port; proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-Port $server_port; proxy_set_header X-Forwarded-Port $server_port;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 60s;
proxy_send_timeout 90s;
proxy_read_timeout 90s;
proxy_buffering off;
proxy_temp_file_write_size 64k;
proxy_pass http://127.0.0.1:6543/; proxy_pass http://127.0.0.1:6543/;
proxy_redirect off;
} }
``` ```
Other Configuration
```
[server:main]
use = egg:waitress#main
host = 0.0.0.0
port = 6543
;port = %(http_port)s digunakan jika port akan menggunakan parameter
trusted_proxy = 10.8.50.23
trusted_proxy_count = 1
trusted_proxy_headers = x-forwarded-for x-forwarded-host x-forwarded-proto x-forwarded-port
clear_untrusted_proxy_headers = yes
url_scheme = https # HTTP or https
```
...@@ -456,7 +456,7 @@ def main(global_config, **settings): ...@@ -456,7 +456,7 @@ def main(global_config, **settings):
config = Configurator(settings=settings, config = Configurator(settings=settings,
root_factory='opensipkd.models.RootFactory', root_factory='opensipkd.models.RootFactory',
session_factory=session_factory) session_factory=session_factory)
config.set_default_csrf_options(require_csrf=True) config.set_default_csrf_options(require_csrf=False)
modules = get_modules(settings) modules = get_modules(settings)
from importlib import import_module from importlib import import_module
for module in modules: for module in modules:
...@@ -499,7 +499,7 @@ def main(global_config, **settings): ...@@ -499,7 +499,7 @@ def main(global_config, **settings):
config.add_request_method(get_ini, 'get_ini', reify=True) config.add_request_method(get_ini, 'get_ini', reify=True)
config.add_request_method(get_csrf_token, 'get_csrf_token', reify=True) config.add_request_method(get_csrf_token, 'get_csrf_token', reify=True)
config.add_translation_dirs('opensipkd.base:locale/') # config.add_translation_dirs('opensipkd.base:locale/')
config.add_static_view('static', 'opensipkd.base:static', config.add_static_view('static', 'opensipkd.base:static',
cache_max_age=3600) cache_max_age=3600)
......
...@@ -22,11 +22,13 @@ from .base_views import BaseView ...@@ -22,11 +22,13 @@ from .base_views import BaseView
from opensipkd.models import ( from opensipkd.models import (
DBSession, UserService, ) DBSession, UserService, )
from .common import DataTables, ColumnDT from .common import DataTables, ColumnDT
from pyramid.csrf import new_csrf_token
_ = TranslationStringFactory('login') _ = TranslationStringFactory('login')
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@view_config(context=HTTPNotFound, renderer='templates/404.pt') @view_config(context=HTTPNotFound, renderer='templates/404.pt')
def not_found(request): def not_found(request):
path = request.path path = request.path
...@@ -150,3 +152,5 @@ two_minutes = timedelta(1.0 / 24 / 60) ...@@ -150,3 +152,5 @@ two_minutes = timedelta(1.0 / 24 / 60)
def deferred_jenis(node, kw): def deferred_jenis(node, kw):
values = kw.get('daftar_jenis', []) values = kw.get('daftar_jenis', [])
return widget.RadioChoiceWidget(values=values) return widget.RadioChoiceWidget(values=values)
...@@ -2,31 +2,25 @@ import logging ...@@ -2,31 +2,25 @@ import logging
import os import os
import re import re
from datetime import datetime from datetime import datetime
from email.utils import parseaddr
import colander
from datatables import ColumnDT from datatables import ColumnDT
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from opensipkd.base.views.upload import tmpstore from deform import (widget, Form, ValidationFailure, FileData, )
from opensipkd.tools.captcha import get_captcha
from opensipkd.tools.report import csv_response, file_response
from pyramid.httpexceptions import HTTPFound, HTTPNotFound from pyramid.httpexceptions import HTTPFound, HTTPNotFound
from .common import DataTables from opensipkd.base.views.upload import tmpstore
from .. import DBSession, get_params, get_urls from opensipkd.tools import dmy, get_settings, get_ext, \
from opensipkd.tools import dmy, date_from_str, get_settings, get_ext, \
date_from_str, get_random_string date_from_str, get_random_string
import colander
from deform import (widget, Form, ValidationFailure, Button, FileData, )
from email.utils import parseaddr
from opensipkd.tools.buttons import btn_save, btn_cancel, btn_close, btn_delete, \ from opensipkd.tools.buttons import btn_save, btn_cancel, btn_close, btn_delete, \
btn_view, btn_add, btn_edit, btn_csv, \ btn_add, btn_csv, \
btn_pdf btn_pdf
from opensipkd.tools.captcha import get_captcha
from opensipkd.models import User, Menus from opensipkd.tools.report import csv_response, file_response
from .common import DataTables
from .. import DBSession, get_params, get_urls
from ..scripts.initializedb import append_csv from ..scripts.initializedb import append_csv
from ..tools.api import auth_from_rpc
from ...detable import DeTable from ...detable import DeTable
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
......
...@@ -83,6 +83,14 @@ ...@@ -83,6 +83,14 @@
href="${home}/reset-password">Lupa Password?</a> href="${home}/reset-password">Lupa Password?</a>
</div> </div>
</section> </section>
<section>
<div tal:condition="'csrf_token' in form">
<div tal:define="field form['csrf_token']" style="display: none;">
${structure:field.serialize()}
</div>
</div>
</section>
</fieldset> </fieldset>
<footer> <footer>
<section> <section>
......
...@@ -9,9 +9,6 @@ ...@@ -9,9 +9,6 @@
<div class="panel-body"> <div class="panel-body">
<div class="col-md-10 col-md-offset-1"> <div class="col-md-10 col-md-offset-1">
<blockquote>
<p>Untuk Background, beri nama background pada file<br>Untuk Logo beri nama logo pada file</p>
</blockquote>
<div tal:content="structure form"/> <div tal:content="structure form"/>
</div> </div>
</div> </div>
......
import os import os
import colander import colander
from deform import ( from deform import (Form, widget, FileData, )
Form,
widget,
FileData,
)
from deform.interfaces import FileUploadTempStore from deform.interfaces import FileUploadTempStore
from opensipkd.tools import (
get_ext,
dict_to_str,
)
from pyramid.httpexceptions import HTTPFound from pyramid.httpexceptions import HTTPFound
from pyramid.view import view_config from pyramid.view import view_config
from opensipkd.tools import (get_ext, dict_to_str, )
from .view_tools import CSRFSchema
from .. import get_urls from .. import get_urls
# from unggah import DbUpload
def route_list(request, p={}): def route_list(request, p={}):
q = dict_to_str(p) q = dict_to_str(p)
return HTTPFound(location=get_urls(request.route_url('upload-logo', _query=q))) return HTTPFound(location=get_urls(request.route_url('upload-logo', _query=q)))
...@@ -43,46 +38,46 @@ def route_list(request, p={}): ...@@ -43,46 +38,46 @@ def route_list(request, p={}):
tmpstore = FileUploadTempStore() tmpstore = FileUploadTempStore()
class AddSchema(colander.Schema): class AddSchema(CSRFSchema):
upload = colander.SchemaNode( upload = colander.SchemaNode(
FileData(), FileData(),
widget=widget.FileUploadWidget(tmpstore), widget=widget.FileUploadWidget(tmpstore),
title='Unggah') title='Unggah')
typ = colander.SchemaNode( image_for = colander.SchemaNode(
colander.String(), colander.String(),
widget=widget.SelectWidget(values=(('img', "Image"), ('icon', "Icon"))), widget=widget.SelectWidget(values=(('oth', "Other"), ('logo', "Logo"),
title='Jenis') ('bg', "Background"))),
title='Peruntukan')
def get_form(schema_cls): def get_form(request, schema_cls):
schema = schema_cls() schema = schema_cls()
schema = schema.bind(request=request)
return Form(schema, buttons=('simpan', 'batal')) return Form(schema, buttons=('simpan', 'batal'))
@view_config(route_name='upload-logo', @view_config(route_name='upload-logo',
renderer='templates/upload.pt', renderer='templates/upload.pt',
permission='upload-logo') permission='upload-logo', require_csrf=True)
def view_file(request): def view_file(request):
form = get_form(AddSchema) form = get_form(request, AddSchema)
if request.POST: if request.POST:
if 'simpan' in request.POST: if 'simpan' in request.POST:
input_file = request.POST['upload'].file input_file = request.POST['upload'].file
filename = request.POST['upload'].filename.lower() filename = request.POST['upload'].filename.lower()
ext = get_ext(filename).lower() ext = get_ext(filename).lower()
if ext.lower() not in ['.png', '.ico']: if ext.lower() not in ['.png', '.ico']:
request.session.flash('File harus format png', 'error') request.session.flash("File harus format 'png' atau 'ico'", 'error')
return dict(form=form.render()) return dict(form=form.render())
_here = os.path.dirname(__file__) _here = os.path.dirname(__file__)
static_path = os.path.join(os.path.dirname(_here), 'static') static_path = os.path.join(os.path.dirname(_here), 'static')
if filename.startswith('logo'): fname = filename
if request.POST["image_for"] == "logo":
fname = f"logo{ext}" fname = f"logo{ext}"
elif filename.startswith('background'): elif request.POST["image_for"] == "bg":
fname = f"background{ext}" fname = f"background{ext}"
else: typ = ext == '.png' and "img" or 'icon'
fname = filename folder = os.path.join(static_path, typ)
folder = os.path.join(static_path, request.POST['typ'])
if not os.path.exists(folder): if not os.path.exists(folder):
os.makedirs(folder) os.makedirs(folder)
...@@ -94,6 +89,7 @@ def view_file(request): ...@@ -94,6 +89,7 @@ def view_file(request):
if not data: if not data:
break break
output_file.write(data) output_file.write(data)
request.session.flash(f"Sukses upload {fname}")
return route_list(request) return route_list(request)
return dict(form=form.render()) return dict(form=form.render())
...@@ -42,11 +42,11 @@ from opensipkd.models import User, ExternalIdentity, Partner ...@@ -42,11 +42,11 @@ from opensipkd.models import User, ExternalIdentity, Partner
from opensipkd.tools import create_now, set_user_log, get_settings from opensipkd.tools import create_now, set_user_log, get_settings
from opensipkd.tools.buttons import btn_cancel from opensipkd.tools.buttons import btn_cancel
from .. import get_urls from .. import get_urls
from .view_tools import CSRFSchema
log = __import__("logging").getLogger(__name__) log = __import__("logging").getLogger(__name__)
class Login(colander.Schema): class Login(CSRFSchema):
username = colander.SchemaNode( username = colander.SchemaNode(
colander.String(), colander.String(),
widget=widget.TextInputWidget( widget=widget.TextInputWidget(
...@@ -57,19 +57,15 @@ class Login(colander.Schema): ...@@ -57,19 +57,15 @@ class Login(colander.Schema):
password = colander.SchemaNode( password = colander.SchemaNode(
colander.String(), widget=widget.PasswordWidget()) colander.String(), widget=widget.PasswordWidget())
# csrf_token = colander.SchemaNode( # def after_bind(self, schema, kwargs):
# colander.String(), # request = kwargs["request"]
# csrf_token = new_csrf_token(request)
# log.error(csrf_token)
# self["csrf_token"] = colander.SchemaNode(
# colander.String(), widget=widget.HiddenWidget(),
# default=csrf_token
# ) # )
def after_bind(self, schema, kwargs):
request = kwargs["request"]
csrf_token = new_csrf_token(request)
log.error(csrf_token)
self["csrf_token"] = colander.SchemaNode(
colander.String(), widget=widget.HiddenWidget(),
default=csrf_token
)
# http://deformdemo.repoze.org/interfield/ # http://deformdemo.repoze.org/interfield/
def login_validator(form, value): def login_validator(form, value):
...@@ -172,7 +168,7 @@ def oauth2_login(request, params=None): ...@@ -172,7 +168,7 @@ def oauth2_login(request, params=None):
class ViewLogin(BaseView): class ViewLogin(BaseView):
@view_config(route_name='login', renderer='templates/form.pt') @view_config(route_name='login', renderer='templates/form.pt', require_csrf=True)
def view_login(self): def view_login(self):
request = self.req request = self.req
request.session["login"] = True request.session["login"] = True
...@@ -247,7 +243,7 @@ class ViewLogin(BaseView): ...@@ -247,7 +243,7 @@ class ViewLogin(BaseView):
request.session.flash(str(e), "error") request.session.flash(str(e), "error")
return render_to_response( return render_to_response(
login_tpl, dict( login_tpl, dict(
form=form.render(), form=form,
message=message, message=message,
url=get_urls(request.route_url('login')), url=get_urls(request.route_url('login')),
next_url=next_url, next_url=next_url,
...@@ -260,17 +256,17 @@ class ViewLogin(BaseView): ...@@ -260,17 +256,17 @@ class ViewLogin(BaseView):
return redirect_login(request, user) return redirect_login(request, user)
# values = {"csrf_token": new_csrf_token(request)} # values = {"csrf_token": new_csrf_token(request)}
login = "" login = ""
if login_tpl == 'templates/login.pt': # if login_tpl == 'templates/login.pt':
return dict(form=form.render(), # return dict(form=form.render(),
message=message, # message=message,
url=get_urls(request.route_url('login')), # url=get_urls(request.route_url('login')),
next_url=next_url, # next_url=next_url,
login=login, ) # login=login, )
return render_to_response( return render_to_response(
renderer_name=login_tpl, renderer_name=login_tpl,
request=request, request=request,
value=dict(form=form.render(), value=dict(form=form,
message=message, message=message,
url=get_urls(request.route_url('login')), url=get_urls(request.route_url('login')),
next_url=next_url, next_url=next_url,
......
import colander
from pyramid.csrf import new_csrf_token, get_csrf_token
from opensipkd.base.views import widget
class CSRFSchema(colander.Schema):
def after_bind(self, schema, kwargs):
request = kwargs["request"]
csrf_token = get_csrf_token(request)
if not csrf_token:
csrf_token = new_csrf_token(request)
self["csrf_token"] = colander.SchemaNode(
colander.String(), widget=widget.HiddenWidget(),
default=csrf_token
)
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
name name|field.name; name name|field.name;
oid oid|field.oid; oid oid|field.oid;
"> ">
<div class="input"> <div class="input">
<input <input
type="password" type="password"
name="${name}" name="${name}"
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
class string: form-control ${css_class|field.widget.css_class or ''}; class string: form-control ${css_class|field.widget.css_class or ''};
attributes|field.widget.attributes|{};" attributes|field.widget.attributes|{};"
id="${oid}"/> id="${oid}"/>
<!--? onkeyup="checkPasswordStrength${oid}();"--> <!--? onkeyup="checkPasswordStrength${oid}();"-->
<div class="checkbox"> <div class="checkbox">
<label> <label>
...@@ -20,23 +20,23 @@ ...@@ -20,23 +20,23 @@
</label> </label>
</div> </div>
<div id="${oid}-password-strength-status"></div> <div id="${oid}-password-strength-status"></div>
</div> </div>
<style> <style>
#password-strength-status { #password-strength-status {
padding: 5px 10px; padding: 5px 10px;
border-radius: 4px; border-radius: 4px;
margin-top: 5px; margin-top: 5px;
}
</style>
<script type="text/javascript">
$('#view${oid}').change(function(){
if ($(this).prop('checked')==true){
$('#${oid}').attr('type','text');
} }
else { </style>
$('#${oid}').attr('type','password'); <script type="text/javascript">
$('#view${oid}').change(function () {
if ($(this).prop('checked') == true) {
$('#${oid}').attr('type', 'text');
} else {
$('#${oid}').attr('type', 'password');
} }
}); });
function checkPasswordStrength${oid}() { function checkPasswordStrength${oid}() {
var number = /([0-9])/; var number = /([0-9])/;
var alphabets = /([a-zA-Z])/; var alphabets = /([a-zA-Z])/;
...@@ -51,14 +51,13 @@ ...@@ -51,14 +51,13 @@
$('#${oid}-password-strength-status').removeClass(); $('#${oid}-password-strength-status').removeClass();
$('#${oid}-password-strength-status').addClass('label label-success'); $('#${oid}-password-strength-status').addClass('label label-success');
$('#${oid}-password-strength-status').html("Strong"); $('#${oid}-password-strength-status').html("Strong");
} } else {
else {
$('#${oid}-password-strength-status').removeClass(); $('#${oid}-password-strength-status').removeClass();
$('#${oid}-password-strength-status').addClass('label label-warning'); $('#${oid}-password-strength-status').addClass('label label-warning');
$('#${oid}-password-strength-status').html("Medium (should include alphabets, numbers and special characters.)"); $('#${oid}-password-strength-status').html("Medium (should include alphabets, numbers and special characters.)");
} }
} }
} }
</script> </script>
</tal:block> </tal:block>
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!