LabHub
배우기 러닝패스 코스

Testing Tools in Practice

An access-control test matrix that finds defects

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

인증 없음·권한 없음·타인 소유·정상 요청을 분리한 부정 테스트를 작성합니다.

왜 중요한가

성공 응답만 확인한 접근 제어 시험이 초록불이었다. 경로에서 Header 주입을 빠뜨리거나 scope 검사를 지워도 시험은 깨지지 않았다. 검증자는 허용 사례만 나열하지 않고 각각의 거절 이유를 따로 관측해야 한다.

단계

  1. /root/work/test-auth-matrix-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: bearer(header)는 정확히 'Bearer '로 시작하고 뒤에 공백 없는 토큰 하나가 있을 때 토큰을 반환합니다. None·빈 토큰·다른 scheme·추가 공백은 ValueError입니다. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.

처음 한 번 준비하세요. 기존 파일은 덮어쓰지 않습니다.

mkdir -p /root/work/test-auth-matrix-lab
test -e /root/work/test-auth-matrix-lab/service.py || cp /opt/fixtures/ten_labs/test-auth-matrix-lab/service.py /root/work/test-auth-matrix-lab/service.py
test -e /root/work/test-auth-matrix-lab/test_service.py || cp /opt/fixtures/ten_labs/test-auth-matrix-lab/test_service.py /root/work/test-auth-matrix-lab/test_service.py
cd /root/work/test-auth-matrix-lab
  1. /root/work/test-auth-matrix-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: principal(token, users)는 토큰 사전의 사용자 {id, scopes}를 반환하되 scopes 리스트까지 복사합니다. 모르는 토큰은 ValueError입니다. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.

  2. /root/work/test-auth-matrix-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: require_scope(user, scope)는 scopes에 scope 문자열이 정확히 있을 때 None, 없으면 PermissionError를 냅니다. read-all은 read가 아닙니다. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.

  3. /root/work/test-auth-matrix-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: visible(user, document)는 document가 None이 아니고 owner가 user의 id와 정확히 같을 때만 True입니다. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.

  4. /root/work/test-auth-matrix-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: public_document(document)는 id와 title만 가진 새 딕셔너리입니다. owner나 internal_cost는 포함하지 않습니다. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.

  5. /root/work/test-auth-matrix-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: authenticate(header, users)는 bearer와 principal을 연결합니다. ValueError는 HTTPException(401)이며 headers의 WWW-Authenticate 값은 Bearer입니다. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.

  6. /root/work/test-auth-matrix-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: read_document(user, documents, document_id)는 read scope 없으면 HTTPException(403), 없거나 남의 문서면 HTTPException(404), 아니면 public_document 결과입니다. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.

  7. /root/work/test-auth-matrix-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: create_app(users, documents)는 GET /documents/{document_id}에서 Authorization 헤더를 받아 authenticate와 read_document를 호출하는 FastAPI 앱을 반환합니다. 200·401·403·404와 비공개 필드 제거를 실제 요청으로 검증하세요. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.

참고

Bearer 헤더를 분리한다 — 테스트

/root/work/test-auth-matrix-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: bearer(header)는 정확히 'Bearer '로 시작하고 뒤에 공백 없는 토큰 하나가 있을 때 토큰을 반환합니다. None·빈 토큰·다른 scheme·추가 공백은 ValueError입니다. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.

처음 한 번 준비하세요. 기존 파일은 덮어쓰지 않습니다.

mkdir -p /root/work/test-auth-matrix-lab
test -e /root/work/test-auth-matrix-lab/service.py || cp /opt/fixtures/ten_labs/test-auth-matrix-lab/service.py /root/work/test-auth-matrix-lab/service.py
test -e /root/work/test-auth-matrix-lab/test_service.py || cp /opt/fixtures/ten_labs/test-auth-matrix-lab/test_service.py /root/work/test-auth-matrix-lab/test_service.py
cd /root/work/test-auth-matrix-lab

헤더를 임의로 여러 조각으로 나누면 공백 오류를 정상 토큰으로 받아들일 수 있습니다. 구현 파일은 수정하지 않습니다. pytest.raises로 예상 예외를 확인하고 정상 결과에는 구체적인 예상값을 단언하세요.

저장 후 bash /opt/lab/checks/test-auth-matrix-lab/01-contract.sh로 확인하세요.

신원을 복사해 반환한다 — 테스트

/root/work/test-auth-matrix-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: principal(token, users)는 토큰 사전의 사용자 {id, scopes}를 반환하되 scopes 리스트까지 복사합니다. 모르는 토큰은 ValueError입니다. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.

반환된 scopes를 수정해 원래 사용자 권한까지 바뀌면 요청 간 권한이 섞입니다. 구현 파일은 수정하지 않습니다. pytest.raises로 예상 예외를 확인하고 정상 결과에는 구체적인 예상값을 단언하세요.

저장 후 bash /opt/lab/checks/test-auth-matrix-lab/02-contract.sh로 확인하세요.

권한은 정확히 비교한다 — 테스트

/root/work/test-auth-matrix-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: require_scope(user, scope)는 scopes에 scope 문자열이 정확히 있을 때 None, 없으면 PermissionError를 냅니다. read-all은 read가 아닙니다. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.

부분 문자열 비교는 더 긴 권한 이름을 다른 권한으로 오해합니다. 구현 파일은 수정하지 않습니다. pytest.raises로 예상 예외를 확인하고 정상 결과에는 구체적인 예상값을 단언하세요.

저장 후 bash /opt/lab/checks/test-auth-matrix-lab/03-contract.sh로 확인하세요.

소유권을 별도로 확인한다 — 테스트

/root/work/test-auth-matrix-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: visible(user, document)는 document가 None이 아니고 owner가 user의 id와 정확히 같을 때만 True입니다. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.

리소스 없음과 타인 소유를 같은 판정으로 묶습니다. 구현 파일은 수정하지 않습니다. pytest.raises로 예상 예외를 확인하고 정상 결과에는 구체적인 예상값을 단언하세요.

저장 후 bash /opt/lab/checks/test-auth-matrix-lab/04-contract.sh로 확인하세요.

응답 필드를 허용 목록으로 고른다 — 테스트

/root/work/test-auth-matrix-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: public_document(document)는 id와 title만 가진 새 딕셔너리입니다. owner나 internal_cost는 포함하지 않습니다. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.

원본에서 필드를 지우지 말고 새 응답을 조립합니다. 구현 파일은 수정하지 않습니다. pytest.raises로 예상 예외를 확인하고 정상 결과에는 구체적인 예상값을 단언하세요.

저장 후 bash /opt/lab/checks/test-auth-matrix-lab/05-contract.sh로 확인하세요.

오류를 HTTP 계약에 맞춘다 — 테스트

/root/work/test-auth-matrix-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: authenticate(header, users)는 bearer와 principal을 연결합니다. ValueError는 HTTPException(401)이며 headers의 WWW-Authenticate 값은 Bearer입니다. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.

인증 실패와 애플리케이션 오류를 500 하나로 뭉치지 않습니다. 구현 파일은 수정하지 않습니다. pytest.raises로 예상 예외를 확인하고 정상 결과에는 구체적인 예상값을 단언하세요.

저장 후 bash /opt/lab/checks/test-auth-matrix-lab/06-contract.sh로 확인하세요.

거절 순서를 고정한다 — 테스트

/root/work/test-auth-matrix-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: read_document(user, documents, document_id)는 read scope 없으면 HTTPException(403), 없거나 남의 문서면 HTTPException(404), 아니면 public_document 결과입니다. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.

인증 이후에도 scope와 소유권은 각각 확인해야 합니다. 구현 파일은 수정하지 않습니다. pytest.raises로 예상 예외를 확인하고 정상 결과에는 구체적인 예상값을 단언하세요.

저장 후 bash /opt/lab/checks/test-auth-matrix-lab/07-contract.sh로 확인하세요.

실제 요청에서 경계를 닫는다 — 테스트

/root/work/test-auth-matrix-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: create_app(users, documents)는 GET /documents/{document_id}에서 Authorization 헤더를 받아 authenticate와 read_document를 호출하는 FastAPI 앱을 반환합니다. 200·401·403·404와 비공개 필드 제거를 실제 요청으로 검증하세요. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.

함수가 따로 맞아도 경로에서 호출을 빠뜨리면 접근 제어는 적용되지 않습니다. 구현 파일은 수정하지 않습니다. pytest.raises로 예상 예외를 확인하고 정상 결과에는 구체적인 예상값을 단언하세요.

저장 후 bash /opt/lab/checks/test-auth-matrix-lab/08-contract.sh로 확인하세요.