mirror of
https://github.com/OpenHands/OpenHands.git
synced 2026-03-22 05:37:20 +08:00
Fix URL encoding in Jira OAuth authorization URLs (#12399)
Co-authored-by: openhands <openhands@all-hands.dev> Co-authored-by: Rohit Malhotra <rohitvinodmalhotra@gmail.com>
This commit is contained in:
committed by
GitHub
parent
8927ac2230
commit
89a6890269
@@ -4,7 +4,7 @@ import json
|
||||
import os
|
||||
import re
|
||||
import uuid
|
||||
from urllib.parse import urlparse
|
||||
from urllib.parse import urlencode, urlparse
|
||||
|
||||
import requests
|
||||
from fastapi import APIRouter, BackgroundTasks, Header, HTTPException, Request, status
|
||||
@@ -371,9 +371,7 @@ async def create_jira_workspace(request: Request, workspace_data: JiraWorkspaceC
|
||||
'prompt': 'consent',
|
||||
}
|
||||
|
||||
auth_url = (
|
||||
f"{JIRA_AUTH_URL}?{'&'.join([f'{k}={v}' for k, v in auth_params.items()])}"
|
||||
)
|
||||
auth_url = f'{JIRA_AUTH_URL}?{urlencode(auth_params)}'
|
||||
|
||||
return JSONResponse(
|
||||
content={
|
||||
@@ -432,9 +430,7 @@ async def create_workspace_link(request: Request, link_data: JiraLinkCreate):
|
||||
'response_type': 'code',
|
||||
'prompt': 'consent',
|
||||
}
|
||||
auth_url = (
|
||||
f"{JIRA_AUTH_URL}?{'&'.join([f'{k}={v}' for k, v in auth_params.items()])}"
|
||||
)
|
||||
auth_url = f'{JIRA_AUTH_URL}?{urlencode(auth_params)}'
|
||||
|
||||
return JSONResponse(
|
||||
content={
|
||||
|
||||
@@ -2,7 +2,7 @@ import json
|
||||
import os
|
||||
import re
|
||||
import uuid
|
||||
from urllib.parse import urlparse
|
||||
from urllib.parse import urlencode, urlparse
|
||||
|
||||
import requests
|
||||
from fastapi import (
|
||||
@@ -316,7 +316,7 @@ async def create_jira_dc_workspace(
|
||||
'response_type': 'code',
|
||||
}
|
||||
|
||||
auth_url = f"{JIRA_DC_AUTH_URL}?{'&'.join([f'{k}={v}' for k, v in auth_params.items()])}"
|
||||
auth_url = f'{JIRA_DC_AUTH_URL}?{urlencode(auth_params)}'
|
||||
|
||||
return JSONResponse(
|
||||
content={
|
||||
@@ -436,7 +436,7 @@ async def create_workspace_link(request: Request, link_data: JiraDcLinkCreate):
|
||||
'state': state,
|
||||
'response_type': 'code',
|
||||
}
|
||||
auth_url = f"{JIRA_DC_AUTH_URL}?{'&'.join([f'{k}={v}' for k, v in auth_params.items()])}"
|
||||
auth_url = f'{JIRA_DC_AUTH_URL}?{urlencode(auth_params)}'
|
||||
|
||||
return JSONResponse(
|
||||
content={
|
||||
|
||||
@@ -1220,3 +1220,60 @@ async def test_validate_workspace_update_permissions_no_current_link(mock_manage
|
||||
|
||||
result = await _validate_workspace_update_permissions('user1', 'test-workspace')
|
||||
assert result == mock_workspace
|
||||
|
||||
|
||||
# Tests for OAuth URL encoding
|
||||
class TestJiraDcOAuthUrlEncoding:
|
||||
"""Tests to verify OAuth authorization URLs are properly URL-encoded."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch('server.routes.integration.jira_dc.get_user_auth')
|
||||
@patch('server.routes.integration.jira_dc.redis_client')
|
||||
@patch('server.routes.integration.jira_dc.JIRA_DC_ENABLE_OAUTH', True)
|
||||
async def test_create_jira_dc_workspace_url_encoding(
|
||||
self, mock_redis, mock_get_auth, mock_request, mock_user_auth
|
||||
):
|
||||
"""Test that create_jira_dc_workspace properly URL-encodes the authorization URL."""
|
||||
mock_get_auth.return_value = mock_user_auth
|
||||
mock_redis.setex.return_value = True
|
||||
workspace_data = JiraDcWorkspaceCreate(
|
||||
workspace_name='test-workspace',
|
||||
webhook_secret='secret',
|
||||
svc_acc_email='svc@test.com',
|
||||
svc_acc_api_key='key',
|
||||
is_active=True,
|
||||
)
|
||||
|
||||
response = await create_jira_dc_workspace(mock_request, workspace_data)
|
||||
content = json.loads(response.body)
|
||||
|
||||
auth_url = content['authorizationUrl']
|
||||
# Verify no raw spaces in the URL (spaces should be encoded as + or %20)
|
||||
assert ' ' not in auth_url
|
||||
# Verify scope parameter contains encoded scopes (+ is valid URL encoding for space)
|
||||
assert 'scope=read%3Ame+read%3Ajira-user+read%3Ajira-work' in auth_url
|
||||
# Verify redirect_uri is properly encoded
|
||||
assert 'redirect_uri=https%3A%2F%2F' in auth_url
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch('server.routes.integration.jira_dc.get_user_auth')
|
||||
@patch('server.routes.integration.jira_dc.redis_client')
|
||||
@patch('server.routes.integration.jira_dc.JIRA_DC_ENABLE_OAUTH', True)
|
||||
async def test_create_workspace_link_url_encoding(
|
||||
self, mock_redis, mock_get_auth, mock_request, mock_user_auth
|
||||
):
|
||||
"""Test that create_workspace_link properly URL-encodes the authorization URL."""
|
||||
mock_get_auth.return_value = mock_user_auth
|
||||
mock_redis.setex.return_value = True
|
||||
link_data = JiraDcLinkCreate(workspace_name='test-workspace')
|
||||
|
||||
response = await create_workspace_link(mock_request, link_data)
|
||||
content = json.loads(response.body)
|
||||
|
||||
auth_url = content['authorizationUrl']
|
||||
# Verify no raw spaces in the URL (spaces should be encoded as + or %20)
|
||||
assert ' ' not in auth_url
|
||||
# Verify scope parameter contains encoded scopes (+ is valid URL encoding for space)
|
||||
assert 'scope=read%3Ame+read%3Ajira-user+read%3Ajira-work' in auth_url
|
||||
# Verify redirect_uri is properly encoded
|
||||
assert 'redirect_uri=https%3A%2F%2F' in auth_url
|
||||
|
||||
@@ -1323,3 +1323,58 @@ async def test_validate_workspace_update_permissions_no_current_link(mock_manage
|
||||
|
||||
result = await _validate_workspace_update_permissions('user1', 'test-workspace')
|
||||
assert result == mock_workspace
|
||||
|
||||
|
||||
# Tests for OAuth URL encoding
|
||||
class TestJiraOAuthUrlEncoding:
|
||||
"""Tests to verify OAuth authorization URLs are properly URL-encoded."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch('server.routes.integration.jira.get_user_auth')
|
||||
@patch('server.routes.integration.jira.redis_client')
|
||||
async def test_create_jira_workspace_url_encoding(
|
||||
self, mock_redis, mock_get_auth, mock_request, mock_user_auth
|
||||
):
|
||||
"""Test that create_jira_workspace properly URL-encodes the authorization URL."""
|
||||
mock_get_auth.return_value = mock_user_auth
|
||||
mock_redis.setex.return_value = True
|
||||
workspace_data = JiraWorkspaceCreate(
|
||||
workspace_name='test-workspace',
|
||||
webhook_secret='secret',
|
||||
svc_acc_email='svc@test.com',
|
||||
svc_acc_api_key='key',
|
||||
is_active=True,
|
||||
)
|
||||
|
||||
response = await create_jira_workspace(mock_request, workspace_data)
|
||||
content = json.loads(response.body)
|
||||
|
||||
auth_url = content['authorizationUrl']
|
||||
# Verify no raw spaces in the URL (spaces should be encoded as + or %20)
|
||||
assert ' ' not in auth_url
|
||||
# Verify scope parameter contains encoded scopes (+ is valid URL encoding for space)
|
||||
assert 'scope=read%3Ame+read%3Ajira-user+read%3Ajira-work' in auth_url
|
||||
# Verify redirect_uri is properly encoded
|
||||
assert 'redirect_uri=https%3A%2F%2F' in auth_url
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch('server.routes.integration.jira.get_user_auth')
|
||||
@patch('server.routes.integration.jira.redis_client')
|
||||
async def test_create_workspace_link_url_encoding(
|
||||
self, mock_redis, mock_get_auth, mock_request, mock_user_auth
|
||||
):
|
||||
"""Test that create_workspace_link properly URL-encodes the authorization URL."""
|
||||
mock_get_auth.return_value = mock_user_auth
|
||||
mock_redis.setex.return_value = True
|
||||
link_data = JiraLinkCreate(workspace_name='test-workspace')
|
||||
|
||||
response = await create_workspace_link(mock_request, link_data)
|
||||
content = json.loads(response.body)
|
||||
|
||||
auth_url = content['authorizationUrl']
|
||||
# Verify no raw spaces in the URL (spaces should be encoded as + or %20)
|
||||
assert ' ' not in auth_url
|
||||
# Verify scope parameter contains encoded scopes (+ is valid URL encoding for space)
|
||||
assert 'scope=read%3Ame+read%3Ajira-user+read%3Ajira-work' in auth_url
|
||||
# Verify redirect_uri is properly encoded
|
||||
assert 'redirect_uri=https%3A%2F%2F' in auth_url
|
||||
|
||||
Reference in New Issue
Block a user