Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Authorization SDK for building protected Web APIs. It allows your endpoints to perform custom authorization and authentication before the request reaches the view function. Then it passes the consumer object to the view function for further processing.
To access protected APIs, clients should authenticate by passing authorizations. For example, a JWT key can be used as follows:
curl 'http://api.example.com/resources' -H 'Authorization: Bearer eyJ1c2VyX2lkIjoxLCJwZXJtaXNzaW9uX2JpdG'
curl 'http://api.example.com/resources?access_token=eyJ1c2VyX2lkIjoxLCJwZXJtaXNzaW9uX2JpdG'
TIP: When utilizing FastAPI, click the lock symbol on Swagger UI to include your JWT. Run
make startup
for a quick preview.
pip install web-auth-sdk
or
git clone https://github.com/yangaound/web-auth-sdk
cd web-auth-sdk && poetry install
Permission list, located in the usr/etc/permissions.json
file:
permissions = [
{'bitmask_idx': 0, 'codename': 'add_order', 'name': 'Can add order', 'service': 'order'},
{'bitmask_idx': 1, 'codename': 'change_order', 'name': 'Can change order', 'service': 'order'},
{'bitmask_idx': 2, 'codename': 'delete_order', 'name': 'Can delete order', 'service': 'order'},
{'bitmask_idx': 3, 'codename': 'view_order', 'name': 'Can view order', 'service': 'order'},
{'bitmask_idx': 4, 'codename': 'add_tickettype', 'name': 'Can add ticket type', 'service': 'order'},
{'bitmask_idx': 5, 'codename': 'change_tickettype', 'name': 'Can change ticket type', 'service': 'order'},
{'bitmask_idx': 6, 'codename': 'view_tickettype', 'name': 'Can view ticket type', 'service': 'order'},
{'bitmask_idx': 7, 'codename': 'delete_tickettype', 'name': 'Can delete ticket type', 'service': 'order'},
]
How to grant permissions?
Permissions are encoded using a bitmask of length n that is a multiple of 24.
Each permission is represented by a 1
at the corresponding bitmask_idx
-th position in the bitmask, indicating that
the permission is granted.
Base64-encoded bitmask
Bitmask | Base64-encoded |
---|---|
111111111111111111111111111111110111111101111111 | /////39/ |
Decoded/Encoded JWT
Decoded JWT:
{
"user_id": 1,
"permission_bitmask": "/////39/",
"iat": 1678798980,
"exp": 1678800187
}
Encoded JWT:
eyJ1c2VyX2lkIjoxLCJwZXJtaXNzaW9uX2JpdG1hc2siOiIvLy8vLzM5LyIsImlhdCI6MTY3ODc5ODk4MCwiZXhwIjoxNjc4ODAwMTg3fQ
import web_auth
@fastapi.get('/tickets')
@web_auth.permissions('view_ticket') # Iterable[str] are acceptable
async def list_tickets() -> list:
return []
import web_auth
from web_auth.django import DjangoBridge
web_auth.configure(bridge_class=DjangoBridge)
@web_auth.permissions('view_ticket')
def list_tickets(request):
pass
urlpatterns = [django.urls.path('list-tickets', list_tickets)]
import web_auth
from web_auth.flask import FlaskBridge
web_auth.configure(bridge_class=FlaskBridge)
@flask.route('/tickets', methods=['GET'])
@web_auth.permissions('view_ticket')
def list_tickets() -> list:
return []
import web_auth
context = web_auth.make_context(bridge_class='web_auth.fastapi.FastapiBridge')
@fastapi.get('/tickets')
@context.permissions('view_ticket')
async def list_tickets() -> list:
return []
import fastapi
import web_auth
@fastapi.get('/profile')
@web_auth.permissions(['view_directory'])
def get_profile(consumer: web_auth.Consumer) -> dict:
return {
'user': consumer.user.dict(),
'directories': 'get_directories(consumer.user.user_id)',
}
import fastapi
import web_auth
@fastapi.post('/some-action')
def some_action(request: fastapi.Request):
# Create a context with fastapi bridge class
context = web_auth.make_context(bridge_class=web_auth.Config.DEFAULT_BRIDGE_CLASS)
# Authorize access with specific permissions (e.g., 'view_directory')
# If this request lacks permission, it will raise `web_auth.AuthException`
_: web_auth.Consumer = context.bridge.access_control(
request=request,
permissions={'view_directory'},
aggregation_type=web_auth.PermissionAggregationTypeEnum.ALL,
)
# Do some action
from typing import Optional
import fastapi
import requests
from web_auth import make_context, Storage, PermissionModel, Context
class RESTStorage(Storage):
def __init__(self, ttl: int, url: str, context: Optional[Context] = None):
self.url = url
super().__init__(ttl=ttl, context=context)
def _load_permissions(self) -> list[PermissionModel]:
return [PermissionModel(**r) for r in requests.get(self.url).json()]
my_context = make_context(
storage_class=RESTStorage,
storage_params={'ttl': 60, 'url': 'http://api.example.com/permissions?format=json'},
)
@fastapi.get('/tickets')
@my_context(['view_ticket', 'change_ticket'])
def get_tickets() -> list[object]:
pass
import pydantic
import fastapi
from web_auth import make_context, Consumer
from web_auth.fastapi import FastapiBridge
class AuthenticatedUser(pydantic.BaseModel):
account: str
class MyFastapiBridge(FastapiBridge):
# Inject your consumer here if it's not inherited from the `web_auth.Consumer`
consumer_class = Consumer
def authenticate(self, request: fastapi.Request) -> Consumer:
# Your authenticate logic here
return Consumer(
permission_bitmask='11101101111',
user=AuthenticatedUser(account='52354342/Jack'),
)
my_context = make_context(bridge_class=MyFastapiBridge)
@fastapi.get('/me')
@my_context([])
def get_profile(consumer: Consumer) -> AuthenticatedUser:
return consumer.user
import fastapi
from web_auth import make_context, BitmaskAuthorization, Consumer, PermissionAggregationTypeEnum
from web_auth.fastapi import FastapiBridge
class MyAuthorization(BitmaskAuthorization):
def authorize(
self,
consumer: Consumer,
permissions: set[str],
aggregation_type: PermissionAggregationTypeEnum,
):
permission_models = self.context.storage.get_permissions()
# Checks whether the `consumer` has the `permissions` in `permission_models`
class MyFastapiBridge(FastapiBridge):
# Inject your Authorization implementation here, it's default to BitmaskAuthorization.
authorization_class = MyAuthorization
# Configurate your customization
my_context = make_context(bridge_class=MyFastapiBridge)
@fastapi.get('/tickets')
@my_context(['view_ticket', 'change_ticket'])
def get_tickets() -> list[object]:
pass
FAQs
authorization SDK used to build protected Web APIs
We found that web-auth-sdk demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.