diff --git a/src/agent/k8s-rest-agent/src/api/auth.py b/src/agent/k8s-rest-agent/src/api/auth.py index 3aad1c63..e69de29b 100644 --- a/src/agent/k8s-rest-agent/src/api/auth.py +++ b/src/agent/k8s-rest-agent/src/api/auth.py @@ -1,67 +0,0 @@ -import base64 -import json -import logging - -from django.contrib.auth import get_user_model -from django.utils.translation import ugettext as _ -from rest_framework import authentication -from rest_framework import exceptions -from rest_framework_jwt.authentication import ( - JSONWebTokenAuthentication as CoreJSONWebTokenAuthentication, -) -from rest_framework_jwt.settings import api_settings - -jwt_decode_handler = api_settings.JWT_DECODE_HANDLER -jwt_get_username_from_payload = api_settings.JWT_PAYLOAD_GET_USERNAME_HANDLER -User = get_user_model() - -LOG = logging.getLogger(__name__) - - -class JSONWebTokenAuthentication(CoreJSONWebTokenAuthentication): - @staticmethod - def _get_or_create_user(user_id, payload=None): - if payload is None: - payload = {} - - user, _ = User.objects.get_or_create( - id=user_id, username=user_id, defaults={"password": user_id} - ) - - return user - - def authenticate_credentials(self, payload): - """ - Returns an active user that matches the payload's user id and email. - """ - username = jwt_get_username_from_payload(payload) - - if not username: - msg = _("Invalid payload.") - raise exceptions.AuthenticationFailed(msg) - - user = self._get_or_create_user(username, payload) - - if not user.is_active: - msg = _("User account is disabled.") - raise exceptions.AuthenticationFailed(msg) - - return user - - -class IstioJWTAuthentication(authentication.BaseAuthentication): - def authenticate(self, request): - token = request.META.get("HTTP_TOKEN", None) - if token is None: - return None - - token += "=" * (-len(token) % 4) - token = base64.b64decode(token) - token = json.loads(token) - user_id = token.get("sub", None) - if user_id is None: - return None - user, _ = User.objects.get_or_create( - id=user_id, username=user_id, defaults={"password": user_id} - ) - return user, None diff --git a/src/agent/k8s-rest-agent/src/api/routes/hello/views.py b/src/agent/k8s-rest-agent/src/api/routes/hello/views.py index 004f5dd3..c8fdde30 100644 --- a/src/agent/k8s-rest-agent/src/api/routes/hello/views.py +++ b/src/agent/k8s-rest-agent/src/api/routes/hello/views.py @@ -3,11 +3,9 @@ from rest_framework import viewsets, status from drf_yasg.utils import swagger_auto_schema -from rest_framework.decorators import action, permission_classes -from rest_framework.permissions import IsAuthenticated +from rest_framework.decorators import action from rest_framework.response import Response -from api.auth import JSONWebTokenAuthentication, IstioJWTAuthentication from api.utils.mixins import PermissionsPerMethodMixin LOG = logging.getLogger(__name__) @@ -15,7 +13,6 @@ class HelloViewSet(PermissionsPerMethodMixin, viewsets.ViewSet): - authentication_classes = (IstioJWTAuthentication,) @swagger_auto_schema( operation_summary="Hello world", operation_description="Hello world" diff --git a/src/api-engine/api/auth.py b/src/api-engine/api/auth.py index 7945a7e5..8ef0f147 100644 --- a/src/api-engine/api/auth.py +++ b/src/api-engine/api/auth.py @@ -8,8 +8,6 @@ from django.core.exceptions import ObjectDoesNotExist from rest_framework import authentication from rest_framework.permissions import BasePermission -from rest_framework.exceptions import AuthenticationFailed -from rest_framework_jwt.serializers import VerifyJSONWebTokenSerializer from api.common.enums import UserRole from api.models import UserProfile @@ -19,45 +17,6 @@ ADMIN_NAME = os.getenv("ADMIN_USERNAME") -class CustomAuthenticate(authentication.BaseAuthentication): - def authenticate(self, request): - authorization = request.META.get("HTTP_AUTHORIZATION", None) - if not authorization or not authorization.startswith("JWT"): - return None - token = authorization.split(" ")[-1] - if token == SUPER_USER_TOKEN: - username = ADMIN_NAME - try: - user = UserProfile.objects.get(username=username) - except ObjectDoesNotExist: - return None - - return user, None - else: - return None - - -class TokenAuth(authentication.BaseAuthentication): - - def authenticate(self, request): - try: - token = request.META.get('HTTP_AUTHORIZATION', None).split()[1] - token = {"token": token} - - valid_data = VerifyJSONWebTokenSerializer().validate(token) - user = valid_data['user'] - # organization = user.organization - # organization_id = user.organization.id - # organization_name = user.organization.name - # request.user. - if user: - return - else: - raise AuthenticationFailed('认证失败') - except Exception: - raise AuthenticationFailed('认证失败') - - class IsAdminAuthenticated(BasePermission): """ Allows access only to authenticated users. diff --git a/src/api-engine/api/routes/agent/views.py b/src/api-engine/api/routes/agent/views.py index 3a7f5467..6e0c7625 100644 --- a/src/api-engine/api/routes/agent/views.py +++ b/src/api-engine/api/routes/agent/views.py @@ -8,12 +8,9 @@ from drf_yasg.utils import swagger_auto_schema from rest_framework import viewsets, status from rest_framework.decorators import action -from rest_framework.exceptions import PermissionDenied from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response -from rest_framework_jwt.authentication import JSONWebTokenAuthentication -from api.auth import IsOperatorAuthenticated, IsAdminAuthenticated from api.common.enums import HostType from api.exceptions import ( ResourceNotFound, @@ -22,7 +19,7 @@ NoResource, ResourceInUse, ) -from api.models import Agent, KubernetesConfig, Organization +from api.models import Agent, KubernetesConfig from api.routes.agent.serializers import ( AgentQuery, AgentListResponse, @@ -33,8 +30,7 @@ AgentInfoSerializer, AgentApplySerializer, ) -from api.utils.common import with_common_response, any_of -from api.auth import TokenAuth +from api.utils.common import with_common_response from api.common import ok, err LOG = logging.getLogger(__name__) @@ -42,18 +38,7 @@ class AgentViewSet(viewsets.ViewSet): """Class represents agent related operations.""" - authentication_classes = (JSONWebTokenAuthentication, TokenAuth) - - # def get_permissions(self): - # if self.action in ["apply", "list", "release", "retrieve"]: - # permission_classes = ( - # IsAuthenticated, - # any_of(IsAdminAuthenticated, IsOperatorAuthenticated), - # ) - # else: - # permission_classes = (IsAuthenticated, IsOperatorAuthenticated) - # - # return [permission() for permission in permission_classes] + permission_classes = [IsAuthenticated, ] @swagger_auto_schema( query_serializer=AgentQuery, diff --git a/src/api-engine/api/routes/chaincode/views.py b/src/api-engine/api/routes/chaincode/views.py index 3cb0f525..16e2ad61 100644 --- a/src/api-engine/api/routes/chaincode/views.py +++ b/src/api-engine/api/routes/chaincode/views.py @@ -4,7 +4,7 @@ from rest_framework import viewsets, status from rest_framework.response import Response from rest_framework.decorators import action -from rest_framework_jwt.authentication import JSONWebTokenAuthentication +from rest_framework.permissions import IsAuthenticated import os import zipfile @@ -20,7 +20,6 @@ from api.lib.peer.chaincode import ChainCode as PeerChainCode from api.common.serializers import PageQuerySerializer -from api.auth import TokenAuth from api.utils.common import with_common_response from api.exceptions import ResourceNotFound @@ -36,7 +35,7 @@ class ChainCodeViewSet(viewsets.ViewSet): """Class represents Channel related operations.""" - authentication_classes = (JSONWebTokenAuthentication, TokenAuth) + permission_classes = [IsAuthenticated, ] @swagger_auto_schema( query_serializer=PageQuerySerializer, @@ -74,7 +73,8 @@ def list(self, request): } for chaincode in chaincodes_pages ] - response = ChaincodeListResponse({"data": chanincodes_list, "total": chaincodes.count()}) + response = ChaincodeListResponse( + {"data": chanincodes_list, "total": chaincodes.count()}) return Response(data=ok(response.data), status=status.HTTP_200_OK) except Exception as e: return Response( @@ -143,7 +143,8 @@ def package(self, request): envs = init_env_vars(peer_node, org) peer_channel_cli = PeerChainCode("v2.2.0", **envs) - res = peer_channel_cli.lifecycle_package(name, version, chaincode_path, language) + res = peer_channel_cli.lifecycle_package( + name, version, chaincode_path, language) os.system("rm -rf {}/*".format(file_path)) os.system("mv {}.tar.gz {}".format(name, file_path)) if res != 0: @@ -162,8 +163,8 @@ def package(self, request): err(e.args), status=status.HTTP_400_BAD_REQUEST ) return Response( - ok("success"), status=status.HTTP_200_OK - ) + ok("success"), status=status.HTTP_200_OK + ) @swagger_auto_schema( method="post", @@ -218,7 +219,8 @@ def query_installed(self, request): timeout = "5s" peer_channel_cli = PeerChainCode("v2.2.0", **envs) - res, installed_chaincodes = peer_channel_cli.lifecycle_query_installed(timeout) + res, installed_chaincodes = peer_channel_cli.lifecycle_query_installed( + timeout) if res != 0: return Response(err("query installed chaincode failed."), status=status.HTTP_400_BAD_REQUEST) except Exception as e: @@ -272,7 +274,8 @@ def approve_for_my_org(self, request): try: channel_name = serializer.validated_data.get("channel_name") chaincode_name = serializer.validated_data.get("chaincode_name") - chaincode_version = serializer.validated_data.get("chaincode_version") + chaincode_version = serializer.validated_data.get( + "chaincode_version") policy = serializer.validated_data.get("policy") # Perhaps the orderer's port is best stored in the database orderer_url = serializer.validated_data.get("orderer_url") @@ -330,7 +333,8 @@ def query_approved(self, request): cc_name = request.data.get("chaincode_name") peer_channel_cli = PeerChainCode("v2.2.0", **envs) - code, content = peer_channel_cli.lifecycle_query_approved(channel_name, cc_name) + code, content = peer_channel_cli.lifecycle_query_approved( + channel_name, cc_name) if code != 0: return Response(err("query_approved failed."), status=status.HTTP_400_BAD_REQUEST) @@ -355,7 +359,8 @@ def check_commit_readiness(self, request): try: channel_name = serializer.validated_data.get("channel_name") chaincode_name = serializer.validated_data.get("chaincode_name") - chaincode_version = serializer.validated_data.get("chaincode_version") + chaincode_version = serializer.validated_data.get( + "chaincode_version") policy = serializer.validated_data.get("policy") # Perhaps the orderer's port is best stored in the database orderer_url = serializer.validated_data.get("orderer_url") @@ -409,7 +414,8 @@ def commit(self, request): try: channel_name = serializer.validated_data.get("channel_name") chaincode_name = serializer.validated_data.get("chaincode_name") - chaincode_version = serializer.validated_data.get("chaincode_version") + chaincode_version = serializer.validated_data.get( + "chaincode_version") policy = serializer.validated_data.get("policy") # Perhaps the orderer's port is best stored in the database orderer_url = serializer.validated_data.get("orderer_url") @@ -444,7 +450,8 @@ def commit(self, request): print(peer_node.port) # port = peer_node.port.all()[0].internal # port = ports[0].internal - peer_address = peer_node.name + "." + org.name + ":" + str(7051) + peer_address = peer_node.name + \ + "." + org.name + ":" + str(7051) peer_address_list.append(peer_address) peer_root_certs.append(peer_tls_cert) @@ -481,7 +488,8 @@ def query_committed(self, request): peer_node = qs.first() envs = init_env_vars(peer_node, org) peer_channel_cli = PeerChainCode("v2.2.0", **envs) - code, chaincodes_commited = peer_channel_cli.lifecycle_query_committed(channel_name, chaincode_name) + code, chaincodes_commited = peer_channel_cli.lifecycle_query_committed( + channel_name, chaincode_name) if code != 0: return Response(err("query committed failed."), status=status.HTTP_400_BAD_REQUEST) except Exception as e: @@ -509,7 +517,8 @@ def init_env_vars(node, org): envs = { "CORE_PEER_TLS_ENABLED": "true", - "CORE_PEER_LOCALMSPID": "{}MSP".format(org_name.capitalize()), # "Org1.cello.comMSP" + # "Org1.cello.comMSP" + "CORE_PEER_LOCALMSPID": "{}MSP".format(org_name.capitalize()), "CORE_PEER_TLS_ROOTCERT_FILE": "{}/{}/peers/{}/tls/ca.crt".format(dir_node, org_name, node.name + "." + org_name), "CORE_PEER_ADDRESS": "{}:{}".format( node.name + "." + org_name, str(7051)), diff --git a/src/api-engine/api/routes/channel/views.py b/src/api-engine/api/routes/channel/views.py index ff6d7ae1..b806f3af 100644 --- a/src/api-engine/api/routes/channel/views.py +++ b/src/api-engine/api/routes/channel/views.py @@ -8,8 +8,8 @@ from rest_framework import viewsets, status from rest_framework.decorators import action from rest_framework.response import Response -from rest_framework_jwt.authentication import JSONWebTokenAuthentication from rest_framework.parsers import MultiPartParser, FormParser, JSONParser +from rest_framework.permissions import IsAuthenticated # from drf_yasg.utils import swagger_auto_schema @@ -20,7 +20,6 @@ from api.config import CELLO_HOME from api.common.serializers import PageQuerySerializer from api.utils.common import with_common_response, parse_block_file, to_dict -from api.auth import TokenAuth from api.lib.configtxgen import ConfigTX, ConfigTxGen from api.lib.peer.channel import Channel as PeerChannel from api.lib.configtxlator.configtxlator import ConfigTxLator @@ -61,7 +60,7 @@ class ChannelViewSet(viewsets.ViewSet): """Class represents Channel related operations.""" - authentication_classes = (JSONWebTokenAuthentication, TokenAuth) + permission_classes = [IsAuthenticated, ] parser_classes = [MultiPartParser, FormParser, JSONParser] @ swagger_auto_schema( diff --git a/src/api-engine/api/routes/file/views.py b/src/api-engine/api/routes/file/views.py index 21446c53..e00d524b 100644 --- a/src/api-engine/api/routes/file/views.py +++ b/src/api-engine/api/routes/file/views.py @@ -8,7 +8,6 @@ from rest_framework import viewsets, status from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response -from rest_framework_jwt.authentication import JSONWebTokenAuthentication from api.auth import IsOperatorAuthenticated, IsAdminAuthenticated from api.exceptions import CustomError @@ -25,7 +24,6 @@ class FileViewSet(viewsets.ViewSet): - authentication_classes = (JSONWebTokenAuthentication,) permission_classes = ( IsAuthenticated, any_of(IsAdminAuthenticated, IsOperatorAuthenticated), diff --git a/src/api-engine/api/routes/general/serializers.py b/src/api-engine/api/routes/general/serializers.py index 32557b7a..88c658ac 100644 --- a/src/api-engine/api/routes/general/serializers.py +++ b/src/api-engine/api/routes/general/serializers.py @@ -1,6 +1,7 @@ # # SPDX-License-Identifier: Apache-2.0 -# + +from api.routes.user.serializers import UserInfoSerializer from rest_framework import serializers @@ -23,6 +24,10 @@ class RegisterResponse(serializers.Serializer): class LoginBody(serializers.Serializer): - orgName = serializers.CharField(help_text="name of Organization") - username = serializers.CharField(help_text="name of user") + email = serializers.CharField(help_text="email of user") password = serializers.CharField(help_text="password of user") + + +class LoginSuccessBody(serializers.Serializer): + token = serializers.CharField(help_text="access token") + user = UserInfoSerializer() diff --git a/src/api-engine/api/routes/general/views.py b/src/api-engine/api/routes/general/views.py index eb4aed88..84a602a9 100644 --- a/src/api-engine/api/routes/general/views.py +++ b/src/api-engine/api/routes/general/views.py @@ -4,10 +4,12 @@ import logging import base64 +from django.contrib.auth import authenticate from rest_framework import viewsets, status +from rest_framework_simplejwt.views import TokenObtainPairView +from rest_framework_simplejwt.tokens import RefreshToken from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned from rest_framework.response import Response -from rest_framework_jwt.views import ObtainJSONWebToken from api.models import UserProfile, Organization from api.routes.general.serializers import ( RegisterBody, @@ -18,21 +20,19 @@ from api.utils import zip_dir from api.common import ok, err from api.config import CELLO_HOME -from api.utils.jwt import jwt_response_payload_handler -from datetime import datetime -from rest_framework_jwt.settings import api_settings - +from .serializers import ( + LoginBody, + LoginSuccessBody, +) LOG = logging.getLogger(__name__) class RegisterViewSet(viewsets.ViewSet): - def create(self, request): try: serializer = RegisterBody(data=request.data) if serializer.is_valid(raise_exception=True): - # username = serializer.validated_data.get("username") email = serializer.validated_data.get("email") orgname = serializer.validated_data.get("orgName") password = serializer.validated_data.get("password") @@ -115,23 +115,23 @@ def _conversion_msp_tls(self, name): return msp, tls -class CustomObtainJSONWebToken(ObtainJSONWebToken): - - def post(self, request): - serializer = self.get_serializer( - data=request.data - ) - if serializer.is_valid(): - user = serializer.object.get('user') or request.user - token = serializer.object.get('token') - response_data = jwt_response_payload_handler(token, user, request) - response = Response(response_data) - if api_settings.JWT_AUTH_COOKIE: - expiration = (datetime.utcnow() + - api_settings.JWT_EXPIRATION_DELTA) - response.set_cookie(api_settings.JWT_AUTH_COOKIE, - token, - expires=expiration, - httponly=True) - return response - return Response(err(serializer.errors), status=status.HTTP_400_BAD_REQUEST) +class CelloTokenObtainPairView(TokenObtainPairView): + def post(self, request, *args, **kwargs): + serializer = LoginBody(data=request.data) + if serializer.is_valid(raise_exception=True): + user = authenticate( + request, + username=serializer.validated_data['email'], + password=serializer.validated_data['password']) + if user is not None: + refresh = RefreshToken.for_user(user) + data = { + 'token': str(refresh.access_token), + 'user': user, + } + response = LoginSuccessBody(instance=data) + return Response( + data=ok(response.data), + status=200, + ) + return super().post(request, *args, **kwargs) diff --git a/src/api-engine/api/routes/network/views.py b/src/api-engine/api/routes/network/views.py index c2fb9a13..cb3ae427 100644 --- a/src/api-engine/api/routes/network/views.py +++ b/src/api-engine/api/routes/network/views.py @@ -9,11 +9,11 @@ from rest_framework import viewsets, status from rest_framework.decorators import action from rest_framework.response import Response +from rest_framework.permissions import IsAuthenticated from drf_yasg.utils import swagger_auto_schema from django.core.paginator import Paginator from django.core.exceptions import ObjectDoesNotExist from api.exceptions import ResourceNotFound, ResourceExists -from rest_framework_jwt.authentication import JSONWebTokenAuthentication from api.routes.network.serializers import ( NetworkQuery, NetworkListResponse, @@ -26,7 +26,6 @@ from api.models import Network, Node, Port from api.config import CELLO_HOME from api.utils import zip_file -from api.auth import TokenAuth from api.lib.agent import AgentHandler from api.common import ok, err import threading @@ -35,8 +34,7 @@ class NetworkViewSet(viewsets.ViewSet): - - authentication_classes = (JSONWebTokenAuthentication, TokenAuth) + permission_classes = [IsAuthenticated, ] def _genesis2base64(self, network): """ @@ -49,7 +47,8 @@ def _genesis2base64(self, network): dir_node = "{}/{}/".format(CELLO_HOME, network) name = "genesis.block" zname = "block.zip" - zip_file("{}{}".format(dir_node, name), "{}{}".format(dir_node, zname)) + zip_file("{}{}".format(dir_node, name), + "{}{}".format(dir_node, zname)) with open("{}{}".format(dir_node, zname), "rb") as f_block: block = base64.b64encode(f_block.read()) return block @@ -124,7 +123,8 @@ def _agent_params(self, pk): info = {} - org_name = org.name if node.type == "peer" else org.name.split(".", 1)[1] + org_name = org.name if node.type == "peer" else org.name.split(".", 1)[ + 1] # get info of node, e.g, tls, msp, config. info["status"] = node.status info["msp"] = node.msp @@ -186,7 +186,8 @@ def create(self, request): pass org = request.user.organization if org.network: - raise ResourceExists(detail="Network exists for the organization") + raise ResourceExists( + detail="Network exists for the organization") orderers = [] peers = [] @@ -199,18 +200,21 @@ def create(self, request): elif node.type == "orderer": orderers[0]["hosts"].append({"name": node.name}) - ConfigTX(name).create(consensus=consensus, orderers=orderers, peers=peers) + ConfigTX(name).create(consensus=consensus, + orderers=orderers, peers=peers) ConfigTxGen(name).genesis() block = self._genesis2base64(name) - network = Network(name=name, consensus=consensus, genesisblock=block) + network = Network( + name=name, consensus=consensus, genesisblock=block) network.save() org.network = network org.save() nodes = Node.objects.filter(organization=org) for node in nodes: try: - threading.Thread(target=self._start_node, args=(node.id,)).start() + threading.Thread(target=self._start_node, + args=(node.id,)).start() except Exception as e: raise e diff --git a/src/api-engine/api/routes/node/views.py b/src/api-engine/api/routes/node/views.py index fa3bf4e3..fbf0e31a 100644 --- a/src/api-engine/api/routes/node/views.py +++ b/src/api-engine/api/routes/node/views.py @@ -16,7 +16,7 @@ from rest_framework.decorators import action from rest_framework.response import Response from rest_framework.parsers import MultiPartParser, FormParser, JSONParser -from rest_framework_jwt.authentication import JSONWebTokenAuthentication +from rest_framework.permissions import IsAuthenticated from api.common.enums import AgentOperation from api.exceptions import CustomError, NoResource, ResourceExists, ResourceInUse @@ -50,7 +50,6 @@ ) from api.tasks import operate_node from api.utils.common import with_common_response -from api.auth import TokenAuth from api.lib.pki import CryptoGen, CryptoConfig from api.utils import zip_dir, zip_file from api.config import ( @@ -68,7 +67,7 @@ class NodeViewSet(viewsets.ViewSet): - authentication_classes = (JSONWebTokenAuthentication, TokenAuth) + permission_classes = [IsAuthenticated, ] parser_classes = [MultiPartParser, FormParser, JSONParser] # Only operator can update node info diff --git a/src/api-engine/api/routes/organization/views.py b/src/api-engine/api/routes/organization/views.py index 5098ab8b..96d03aeb 100644 --- a/src/api-engine/api/routes/organization/views.py +++ b/src/api-engine/api/routes/organization/views.py @@ -45,8 +45,6 @@ class OrganizationViewSet(viewsets.ViewSet): """Class represents orgnization related operations.""" - # authentication_classes = (JSONWebTokenAuthentication, TokenAuth) - # permission_classes = (IsAuthenticated, IsOperatorAuthenticated) @swagger_auto_schema( query_serializer=OrganizationQuery, @@ -147,9 +145,11 @@ def _create_node(self, org, num, nodeType): :return: null """ for i in range(num): - nodeName = "peer" + str(i) if nodeType == "peer" else "orderer" + str(i) + nodeName = "peer" + \ + str(i) if nodeType == "peer" else "orderer" + str(i) self._generate_config(nodeType, org.name, nodeName) - msp, tls, cfg = self._conversion_msp_tls_cfg(nodeType, org.name, nodeName) + msp, tls, cfg = self._conversion_msp_tls_cfg( + nodeType, org.name, nodeName) urls = "{}.{}".format(nodeName, org.name) node = Node( name=nodeName, @@ -193,7 +193,8 @@ def _conversion_msp_tls_cfg(self, type, org, node): with open("{}tls.zip".format(dir_node), "rb") as f_tls: tls = base64.b64encode(f_tls.read()) - zip_file("{}{}".format(dir_node, name), "{}{}".format(dir_node, cname)) + zip_file("{}{}".format(dir_node, name), + "{}{}".format(dir_node, cname)) with open("{}{}".format(dir_node, cname), "rb") as f_cfg: cfg = base64.b64encode(f_cfg.read()) except Exception as e: @@ -216,8 +217,10 @@ def _generate_config(self, type, org, node): if type == "peer": args.update({"peer_id": "{}.{}".format(node, org)}) args.update({"peer_address": "{}.{}:{}".format(node, org, 7051)}) - args.update({"peer_gossip_externalEndpoint": "{}.{}:{}".format(node, org, 7051)}) - args.update({"peer_chaincodeAddress": "{}.{}:{}".format(node, org, 7052)}) + args.update( + {"peer_gossip_externalEndpoint": "{}.{}:{}".format(node, org, 7051)}) + args.update( + {"peer_chaincodeAddress": "{}.{}:{}".format(node, org, 7052)}) args.update({"peer_tls_enabled": True}) args.update({"peer_localMspId": "{}MSP".format(org.capitalize())}) @@ -225,7 +228,8 @@ def _generate_config(self, type, org, node): a.peer(node, **args) else: args.update({"General_ListenPort": 7050}) - args.update({"General_LocalMSPID": "{}OrdererMSP".format(org.capitalize())}) + args.update( + {"General_LocalMSPID": "{}OrdererMSP".format(org.capitalize())}) args.update({"General_TLS_Enabled": True}) args.update({"General_BootstrapFile": "genesis.block"}) diff --git a/src/api-engine/api_engine/settings.py.example b/src/api-engine/api_engine/settings.py.example index 338ad4fa..9e53a2dc 100644 --- a/src/api-engine/api_engine/settings.py.example +++ b/src/api-engine/api_engine/settings.py.example @@ -49,6 +49,7 @@ INSTALLED_APPS = [ "rest_auth", "rest_auth.registration", "corsheaders", + "rest_framework_simplejwt", ] MIDDLEWARE = [ @@ -145,7 +146,7 @@ REST_FRAMEWORK = { ], "EXCEPTION_HANDLER": "api.utils.custom_exception_handler", "DEFAULT_AUTHENTICATION_CLASSES": ( - "rest_framework_jwt.authentication.JSONWebTokenAuthentication", + "rest_framework_simplejwt.authentication.JWTAuthentication", ), } @@ -165,11 +166,6 @@ REST_USE_JWT = True AUTH_USER_MODEL = 'api.UserProfile' -JWT_AUTH = { - 'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7), - 'JWT_RESPONSE_PAYLOAD_HANDLER': 'api.utils.jwt.jwt_response_payload_handler', -} - SWAGGER_SETTINGS = { # For validating your swagger schema(setting None to not validate) "VALIDATOR_URL": None, @@ -218,3 +214,27 @@ MEDIA_ROOT = "/var/www/media" MEDIA_URL = "$WEBROOT/media/" CELERY_BROKER_URL = "$CELERY_BROKER_URL" + +SIMPLE_JWT = { + 'ROTATE_REFRESH_TOKENS': False, + 'BLACKLIST_AFTER_ROTATION': False, + 'UPDATE_LAST_LOGIN': False, + + 'ALGORITHM': 'HS256', + 'SIGNING_KEY': SECRET_KEY, + 'VERIFYING_KEY': None, + 'AUDIENCE': None, + 'ISSUER': None, + 'JWK_URL': None, + 'LEEWAY': 0, + + 'AUTH_HEADER_TYPES': ('c', 'JWT'), + 'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION', + 'USER_ID_FIELD': 'id', + 'USER_ID_CLAIM': 'user_id', + 'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule', + + 'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',), + 'TOKEN_TYPE_CLAIM': 'token_type', + 'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser', +} diff --git a/src/api-engine/api_engine/urls.py b/src/api-engine/api_engine/urls.py index 00535767..2dc70e61 100644 --- a/src/api-engine/api_engine/urls.py +++ b/src/api-engine/api_engine/urls.py @@ -24,7 +24,10 @@ from drf_yasg import openapi from drf_yasg.views import get_schema_view from rest_framework.routers import DefaultRouter -from rest_framework_jwt.views import verify_jwt_token +from rest_framework_simplejwt.views import ( + TokenObtainPairView, + TokenRefreshView, +) from django.conf.urls.static import static from api.routes.network.views import NetworkViewSet @@ -33,9 +36,10 @@ from api.routes.organization.views import OrganizationViewSet from api.routes.user.views import UserViewSet from api.routes.file.views import FileViewSet -from api.routes.general.views import RegisterViewSet, CustomObtainJSONWebToken +from api.routes.general.views import RegisterViewSet from api.routes.channel.views import ChannelViewSet from api.routes.chaincode.views import ChainCodeViewSet +from api.routes.general.views import CelloTokenObtainPairView DEBUG = getattr(settings, "DEBUG") @@ -66,7 +70,6 @@ router.register("organizations", OrganizationViewSet, basename="organization") router.register("users", UserViewSet, basename="user") router.register("files", FileViewSet, basename="file") -# router.register("login2", LoginViewSet, basename="login2") router.register("register", RegisterViewSet, basename="register") router.register("channels", ChannelViewSet, basename="channel") router.register("chaincodes", ChainCodeViewSet, basename="chaincode") @@ -74,9 +77,8 @@ urlpatterns = router.urls urlpatterns += [ - # path("auth", obtain_jwt_token), - path("token-verify", verify_jwt_token), - path("login", CustomObtainJSONWebToken.as_view()), + path('login', CelloTokenObtainPairView.as_view(), name='token_obtain_pair'), + path('login/refresh/', TokenRefreshView.as_view(), name='token_refresh'), path("docs/", SchemaView.with_ui("swagger", cache_timeout=0), name="docs"), path("redoc/", SchemaView.with_ui("redoc", cache_timeout=0), name="redoc"), ] diff --git a/src/api-engine/requirements.txt b/src/api-engine/requirements.txt index 6a5d19c2..161bcc29 100644 --- a/src/api-engine/requirements.txt +++ b/src/api-engine/requirements.txt @@ -14,7 +14,7 @@ django-extensions==2.2.9 django-filter==2.4.0 django-rest-auth==0.9.5 djangorestframework==3.11.2 -djangorestframework-jwt==1.11.0 +djangorestframework-simplejwt==5.2.2 docker==4.2.0 drf-yasg==1.17.1 flex==6.14.1