Skip to content

Commit

Permalink
[CE-115] Refine user auth api code structure
Browse files Browse the repository at this point in the history
Refine user auth api
Add user login history
Move models into modules directory

Change-Id: Ibd6058d72a4a8f97126073874b4a420f2eaf8b13
Signed-off-by: Haitao Yue <hightall@me.com>
  • Loading branch information
hightall committed Aug 20, 2017
1 parent ffa7404 commit 147f223
Show file tree
Hide file tree
Showing 20 changed files with 270 additions and 150 deletions.
17 changes: 9 additions & 8 deletions src/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,22 @@
#
# SPDX-License-Identifier: Apache-2.0
#
import logging
import os
from common import log_handler, LOG_LEVEL

import bcrypt
from flask import Flask, render_template, redirect, url_for
from flask_login import LoginManager
from mongoengine import connect

from common import log_handler, LOG_LEVEL
from modules.models import ADMIN
from resources import bp_index, \
bp_stat_view, bp_stat_api, \
bp_cluster_view, bp_cluster_api, \
bp_host_view, bp_host_api, bp_auth_api, \
bp_login, bp_user_api, bp_user_view
from resources.models import ADMIN
from mongoengine import connect
from flask_login import LoginManager, UserMixin, login_required
from resources.user import User
from resources import models
import bcrypt
import logging
from modules.user import User

logger = logging.getLogger(__name__)
logger.setLevel(LOG_LEVEL)
Expand Down
7 changes: 7 additions & 0 deletions src/modules/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

# Copyright IBM Corp, All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
from .user import ADMIN, OPERATOR, COMMON_USER, \
User, LoginHistory
8 changes: 7 additions & 1 deletion src/resources/models.py → src/modules/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import os
import datetime
from mongoengine import Document, StringField,\
BooleanField, DateTimeField, IntField
BooleanField, DateTimeField, IntField, \
ReferenceField

sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))

Expand All @@ -19,3 +20,8 @@ class User(Document):
role = IntField(default=COMMON_USER)
timestamp = DateTimeField(default=datetime.datetime.now)
balance = IntField(default=0)


class LoginHistory(Document):
time = DateTimeField(default=datetime.datetime.now)
user = ReferenceField(User)
5 changes: 4 additions & 1 deletion src/modules/user/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@
#
# SPDX-License-Identifier: Apache-2.0
#
from .management import ListUser, CreateUser, UpdateUser, DeleteUser
from .management import ListUser, CreateUser, UpdateUser, \
DeleteUser, UserInfo
from .auth import Register, Login
from .user import User
7 changes: 7 additions & 0 deletions src/modules/user/auth/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

# Copyright IBM Corp, All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
from .register import Register
from .login import Login
69 changes: 69 additions & 0 deletions src/modules/user/auth/login.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@

# Copyright IBM Corp, All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
from flask_restful import Resource, reqparse, fields, marshal_with
from flask import url_for
from flask_login import login_user, logout_user
import logging
import sys
import os
import bcrypt

sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
from common import log_handler, LOG_LEVEL
from modules.user.user import User

logger = logging.getLogger(__name__)
logger.setLevel(LOG_LEVEL)
logger.addHandler(log_handler)

login_fields = {
"success": fields.Boolean,
"id": fields.String,
"next": fields.String,
"error": fields.String
}

login_parser = reqparse.RequestParser()
login_parser.add_argument('username', required=True,
location='form',
help='Username for create')
login_parser.add_argument('password', required=True,
location='form',
help='Password for create')


class Login(Resource):
@marshal_with(login_fields)
def post(self, **kwargs):
args = login_parser.parse_args()
username, password = args["username"], args["password"]

user_obj = User()
try:
user = user_obj.get_by_username_w_password(username)
if bcrypt.checkpw(password.encode('utf8'),
bytes(user.password.encode())):
login_user(user)
user_id = str(user.id)
data = {
"success": True,
"id": user_id,
"next": url_for('bp_index.show')
}
return data, 200
else:
data = {
"success": False,
"error": "Wrong username or password"
}
return data, 401
except Exception as exc:
logger.info("error {}".format(exc))
data = {
"success": False,
"error": "login failed"
}
return data, 401
68 changes: 68 additions & 0 deletions src/modules/user/auth/register.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@

# Copyright IBM Corp, All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
from flask_restful import Resource, reqparse, fields, marshal_with
from flask_login import login_required
import logging
import sys
import os
from flask import current_app as app
import bcrypt

sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
from common import log_handler, LOG_LEVEL
from modules.models import ADMIN
from modules.user.user import User

logger = logging.getLogger(__name__)
logger.setLevel(LOG_LEVEL)
logger.addHandler(log_handler)

register_fields = {
"username": fields.String,
"apikey": fields.String,
"isActivated": fields.Boolean,
"balance": fields.Integer,
"success": fields.Boolean,
"error": fields.String
}

register_parser = reqparse.RequestParser()
register_parser.add_argument('username', required=True,
location='form',
help='Username for create')
register_parser.add_argument('password', required=True,
location='form',
help='Password for create')


class Register(Resource):
@login_required
@marshal_with(register_fields)
def post(self, **kwargs):
args = register_parser.parse_args()
username, password = args["username"], args["password"]
salt = app.config.get("SALT", b"")
password = bcrypt.hashpw(password.encode('utf8'), bytes(salt.encode()))

try:
user = User(username, password)
user_id = user.save()
user = user.get_by_id(user_id)
data = {
"username": user.username,
"apikey": str(user.id),
"isActivated": user.active,
"balance": user.balance,
"success": True
}
return data, 200
except Exception as exc:
logger.error("exc %s", exc)
data = {
"success": False,
"error": "register failed"
}
return data, 400
1 change: 1 addition & 0 deletions src/modules/user/management/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
from .create import CreateUser
from .update import UpdateUser
from .delete import DeleteUser
from .info import UserInfo
4 changes: 2 additions & 2 deletions src/modules/user/management/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@

sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
from common import log_handler, LOG_LEVEL
from resources.models import ADMIN
from resources.user import User
from modules.models import ADMIN
from modules.user.user import User

logger = logging.getLogger(__name__)
logger.setLevel(LOG_LEVEL)
Expand Down
2 changes: 1 addition & 1 deletion src/modules/user/management/delete.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
from common import log_handler, LOG_LEVEL
from resources.models import User as UserModel
from modules.models import User as UserModel

logger = logging.getLogger(__name__)
logger.setLevel(LOG_LEVEL)
Expand Down
46 changes: 46 additions & 0 deletions src/modules/user/management/info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@

# Copyright IBM Corp, All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
from flask_restful import Resource, fields, marshal_with
from flask_login import login_required
import logging
import sys
import os

sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
from common import log_handler, LOG_LEVEL
from modules.user.user import User

logger = logging.getLogger(__name__)
logger.setLevel(LOG_LEVEL)
logger.addHandler(log_handler)

user_info_fields = {
"username": fields.String,
"apikey": fields.String,
"isActivated": fields.Boolean,
"balance": fields.Integer,
"success": fields.Boolean,
"error": fields.String
}


class UserInfo(Resource):
@marshal_with(user_info_fields)
def get(self, user_id):
user_obj = User()
user = user_obj.get_by_id(user_id)
if not user:
return {"error": "No such User", "success": False}, 400

data = {
"username": user.username,
"apikey": str(user.id),
"isActivated": user.active,
"balance": user.balance,
"success": True
}

return data, 200
2 changes: 1 addition & 1 deletion src/modules/user/management/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
from common import log_handler, LOG_LEVEL
from resources.models import User as UserModel
from modules.models import User as UserModel
import time

logger = logging.getLogger(__name__)
Expand Down
2 changes: 1 addition & 1 deletion src/modules/user/management/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
from common import log_handler, LOG_LEVEL
from resources.models import User as UserModel
from modules.models import User as UserModel

logger = logging.getLogger(__name__)
logger.setLevel(LOG_LEVEL)
Expand Down
23 changes: 13 additions & 10 deletions src/resources/user.py → src/modules/user/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import logging
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
from flask_login import UserMixin, AnonymousUserMixin
from resources import models
from modules.models import User as UserModel
from modules.models import LoginHistory
from common import log_handler, LOG_LEVEL

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -32,19 +33,19 @@ def user_role(self):
return self.role

def save(self):
new_user = models.User(username=self.username,
password=self.password,
active=self.active,
role=self.role,
balance=self.balance,
isAdmin=self.isAdmin)
new_user = UserModel(username=self.username,
password=self.password,
active=self.active,
role=self.role,
balance=self.balance,
isAdmin=self.isAdmin)
new_user.save()
self.id = str(new_user.id)
return self.id

def get_by_username(self, username):

dbUser = models.User.objects.get(username=username)
dbUser = UserModel.objects.get(username=username)
if dbUser:
self.username = dbUser.username
self.active = dbUser.active
Expand All @@ -56,7 +57,7 @@ def get_by_username(self, username):

def get_by_username_w_password(self, username):
try:
dbUser = models.User.objects.get(username=username)
dbUser = UserModel.objects.get(username=username)

if dbUser:
self.username = dbUser.username
Expand All @@ -65,6 +66,8 @@ def get_by_username_w_password(self, username):
self.id = dbUser.id
self.isAdmin = dbUser.isAdmin
self.balance = dbUser.balance
login_history = LoginHistory(user=dbUser)
login_history.save()
return self
else:
return None
Expand All @@ -74,7 +77,7 @@ def get_by_username_w_password(self, username):

def get_by_id(self, id):
try:
dbUser = models.User.objects.get(id=id)
dbUser = UserModel.objects.get(id=id)
except Exception:
return None
else:
Expand Down
3 changes: 1 addition & 2 deletions src/resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from .host_view import bp_host_view

from .stat import bp_stat_api, bp_stat_view
from .auth_api import bp_auth_api
from .login import bp_login
from .user_api import bp_user_api
from .user_api import bp_user_api, bp_auth_api
from .user_view import bp_user_view
Loading

0 comments on commit 147f223

Please sign in to comment.