swp-fu-eid / eid-fu-swp

Docker-based REST API implemented with Django and restframework.
MIT License
2 stars 1 forks source link

Add Openid provider and interface to eid #78

Closed BenjaminKeller closed 6 years ago

BenjaminKeller commented 6 years ago

This is the clean successor of #67. @zervnet @nils-wisiol Please review.

This implements the following steps. It can be testet by executing:

docker-compose up --build
./setup_testenvironment.sh

Using this .env file:

BOILERPLATE_DOMAIN=eid.local

# network
BOILERPLATE_IPV4_16PREFIX=10.0
BOILERPLATE_IPV6_SUBNET=bade:affe:dead:beef:b011::/80
BOILERPLATE_IPV6_ADDRESS=bade:affe:dead:beef:b011:0642:ac10:0080

# certificates
BOILERPLATE_WWW_CERTS=C:\Users\keller\certs

# API-related
BOILERPLATE_API_SECRETKEY=kjdf8wu4jklsd3
BOILERPLATE_DB_PASSWORD=sdfklj34w34jlkj

# OIDC Provider Test
OIDC_RESPONSE_TYPE=id_token token
OIDC_SCOPE=openid
OIDC_CLIENT_ID=123456
OIDC_REDIRECT_URI=http://localhost:3000
OIDC_AUTHORITY_URL=https://eid.local/api/openid
OIDC_TCTOKEN_ID=d454e1bd5757450bca0b4b9bd99a0a48
OIDC_SESSION_ID=000e80181f0b41edbd95d1fac39cff25
OIDC_REFRESH_ID=cd55df0f4a7d4a94b9ab59c3e04c1ead
OIDC_ACCESS_TOKEN=99fd6f8c639c40529104ef9111035fbc
OIDC_RESTRICTED_ID=deadbeef
OIDC_STATE=b80525634e3e416b869fd421b76d087c
OIDC_NONCE=a8ebe80b194240f8ae301e2f3df8b43d
OIDC_OPENID_PARAMETER=next=%2Fapi%2Fopenid%2Fauthorize%3Fclient_id%3D123456%26redirect_uri%3Dhttp%253A%252F%252Flocalhost%253A3000%26response_type%3Did_token%2520token%26scope%3Dopenid%26state%3Db80525634e3e416b869fd421b76d087c%26nonce%3Da8ebe80b194240f8ae301e2f3df8b43d%26display%3Dpopup

# Example OIDC-Client
CLIENT_ID=123456
AUTHORITY_URL=https://eid.local/api/openid
REDIRECT_URL=http://localhost:3000

Use the provided links to see an example.

1. Step: Client (KVV) --> OpenID Plugin

Send OpenID Connect Authorization Request:

HTTP/1.1 302 Found
  Location: **https://eid.local/api/openid/authorize**
  response_type=code
  &scope=openid%20profile%20email
  &client_id=SDFGHJKLUZTREDFGHJ
  &state=34790876543456789765
  &redirect_uri=**https://KVV.de/login**

Demo-Link: The client is not part of this pr. Redirects to: https://eid.local/api/openid/authorize?response_type=id_token%20token&scope=openid&client_id=123456&state=b80525634e3e416b869fd421b76d087c&nonce=a8ebe80b194240f8ae301e2f3df8b43d&redirect_uri=http://localhost:3000

2. Step: OpenID Plugin --> OpenID Provider

The plugin redirects to our provider.

HTTP/1.1 302 Found
  Location: **https://eid.local/api/eidopenid/auth**
  response_type=code
  &scope=openid%20profile%20email
  &client_id=SDFGHJKLUZTREDFGHJ
  &state=34790876543456789765
  &redirect_uri=**https://KVV.de/login**

Demo-Link: https://eid.local/api/openid/authorize?response_type=id_token%20token&scope=openid&client_id=123456&state=b80525634e3e416b869fd421b76d087c&nonce=a8ebe80b194240f8ae301e2f3df8b43d&redirect_uri=http://localhost:3000 Redirects to: https://eid.local/api/eidopenid/auth?next=/api/openid/authorize%3Fresponse_type%3Did_token%2520token%26scope%3Dopenid%26client_id%3D123456%26state%3Db80525634e3e416b869fd421b76d087c%26nonce%3Da8ebe80b194240f8ae301e2f3df8b43d%26redirect_uri%3Dhttp%3A//localhost%3A3000

3. Step: OpenID Provider --> eID Service:

Redirect the Authorization Request to the eID Service:

HTTP/1.1 302 Found
  Location: **https://eid.local/api/eIdService/init**
  response_type=code
  &scope=openid%20profile%20email
  &client_id=SDFGHJKLUZTREDFGHJ
  &state=34790876543456789765
  &redirect_uri=**https://KVV.de/login**

Demo-Link: https://eid.local/api/eidopenid/auth?next=/api/openid/authorize%3Fresponse_type%3Did_token%2520token%26scope%3Dopenid%26client_id%3D123456%26state%3Db80525634e3e416b869fd421b76d087c%26nonce%3Da8ebe80b194240f8ae301e2f3df8b43d%26redirect_uri%3Dhttp%3A//localhost%3A3000 Redirects to: https://eid.local/api/eIdService/init?next=%2Fapi%2Fopenid%2Fauthorize%3Fresponse_type%3Did_token%2520token%26scope%3Dopenid%26client_id%3D123456%26state%3Db80525634e3e416b869fd421b76d087c%26nonce%3Da8ebe80b194240f8ae301e2f3df8b43d%26redirect_uri%3Dhttp%3A%2F%2Flocalhost%3A3000

eID-Service Magic

After that, the authentication with the eid server happens and the AusweisApp redirects back to the eID-Service, finally. The following shows the details:

Checker (click on continue anyway...): https://eid.local/check/?next=%2Fapi%2Fopenid%2Fauthorize%3Fresponse_type%3Did_token%2520token%26scope%3Dopenid%26client_id%3D123456%26state%3Db80525634e3e416b869fd421b76d087c%26nonce%3Da8ebe80b194240f8ae301e2f3df8b43d%26redirect_uri%3Dhttp%3A%2F%2Flocalhost%3A3000 eID-Service returns tc token url: http://127.0.0.1:24727/eID-Client?tcTokenUrl=https://eid.local/api/eIdService/getTcToken?tcTokenId=d454e1bd5757450bca0b4b9bd99a0a48 Tc Token (open https://eid.local/api/eIdService/getTcToken?tcTokenId=d454e1bd5757450bca0b4b9bd99a0a48):

<TCTokenType>
  <ServerAddress>https://eid.local/api/eID</ServerAddress>
  <SessionIdentifier>000e8018-1f0b-41ed-bd95-d1fac39cff25</SessionIdentifier>
  <RefreshAddress>
    https://eid.local/api/eIdService/refresh?refreshId=cd55df0f-4a7d-4a94-b9ab-59c3e04c1ead
  </RefreshAddress>
  <CommunicationErrorAddress>https://eid.local/api/eIdService/error</CommunicationErrorAddress>
  <Binding>urn:liberty:paos:2006-08</Binding>
</TCTokenType>

Refresh Address: https://eid.local/api/eIdService/refresh?refreshId=cd55df0f-4a7d-4a94-b9ab-59c3e04c1ead

4. Step: eID Service --> OpenID Provider:

The refresh address redirects to view api/eidopenid/login that receives the Authorization Request plus eID-AccessToken:

HTTP/1.1 302 Found
  Location: **https://eid.local/api/eidopenid/login**
  response_type=code
  &scope=openid%20profile%20email
  &client_id=SDFGHJKLUZTREDFGHJ
  &state=34790876543456789765
  &redirect_uri=**https://KVV.de/login**
  &eid_access_token=uid4 

Demo-Link: https://eid.local/api/eIdService/refresh?refreshId=cd55df0f-4a7d-4a94-b9ab-59c3e04c1ead Redirects to: https://eid.local/api/eidopenid/login/?eid_access_token=6818aaab-e4f0-41d6-a4bf-a03b30424cab&next=%2Fapi%2Fopenid%2Fauthorize%3Fresponse_type%3Did_token%2520token%26scope%3Dopenid%26client_id%3D123456%26state%3Db80525634e3e416b869fd421b76d087c%26nonce%3Da8ebe80b194240f8ae301e2f3df8b43d%26redirect_uri%3Dhttp%3A%2F%2Flocalhost%3A3000

5. Step: OpenID Provider <--> eID Service:

OpenID Provider gets userID from eID-Service by calling python function:

// returns b'deadbeef'
user_id = eid_service.openid_interface.get_user_id(request.GET.get('eid_access_token',''))

6. Step: OpenID Provider --> Client (KVV)

Send OpenID Connect Access Token Response to Client (KVV):

HTTP/1.1 200 OK
  Content-Type: application/json
  Cache-Control: no-store
  Pragma: no-cache
  {
  "access_token": "4vfKjkM8FcGvnzZUN4_KSP0aAp",
  "token_type": "Bearer",
  "expires_in": 3600,
  "id_token": "eyJhb...cifQ.ew...fQ.gg...zqg"
  "user_id": "deadbeef"
  }

Demo-Link: https://eid.local/api/eidopenid/login/?eid_access_token=6818aaab-e4f0-41d6-a4bf-a03b30424cab&next=%2Fapi%2Fopenid%2Fauthorize%3Fresponse_type%3Did_token%2520token%26scope%3Dopenid%26client_id%3D123456%26state%3Db80525634e3e416b869fd421b76d087c%26nonce%3Da8ebe80b194240f8ae301e2f3df8b43d%26redirect_uri%3Dhttp%3A%2F%2Flocalhost%3A3000 Redirects to: http://localhost:3000/#access_token=36e4583e06ae4f918483e050deacf3ca&id_token=eyJhbGciOiJSUzI1NiIsImtpZCI6ImM2NzJiZWQ5OTgyZWI4MDMzODJmNmYxNzdjMDI3MGYwIn0.eyJpc3MiOiJodHRwczovL2VpZC5sb2NhbC9hcGkvb3BlbmlkIiwic3ViIjoiMSIsImF1ZCI6IjEyMzQ1NiIsImV4cCI6MTUwNjU5MDkxNSwiaWF0IjoxNTA2NTkwMzE1LCJhdXRoX3RpbWUiOjE1MDY1OTAzMTQsIm5vbmNlIjoiYThlYmU4MGIxOTQyNDBmOGFlMzAxZTJmM2RmOGI0M2QiLCJhdF9oYXNoIjoidU1fSWVKZV9KTjI3UFR0ekMzVXlEdyIsInVzZXJuYW1lIjoiYidkZWFkYmVlZicifQ.PHYIeT9a94vhJaxpxBix8AeM296zfOHiTHBo5977xk3ggUGhhqKQIzNz7T1dEEmDmFRb3rWSbl6oxblegNxke4VkzuqNOfA7l7xAzQ6XcMVVOqTMAIxLdDex9LgFD7yIX1yvMo2pwQx8AuSy8eNiJAjEGXYm9sIrijTSQpfVThM&token_type=bearer&expires_in=3600&state=b80525634e3e416b869fd421b76d087c

[Optional] Read id token

Open https://jwt.io/ and paste the id token. The username can be read from the payload. The signature cannot be verified using this website. See the tests for information about verifying a token. ID Token:

eyJhbGciOiJSUzI1NiIsImtpZCI6ImM2NzJiZWQ5OTgyZWI4MDMzODJmNmYxNzdjMDI3MGYwIn0.eyJpc3MiOiJodHRwczovL2VpZC5sb2NhbC9hcGkvb3BlbmlkIiwic3ViIjoiMSIsImF1ZCI6IjEyMzQ1NiIsImV4cCI6MTUwNjU5MDkxNSwiaWF0IjoxNTA2NTkwMzE1LCJhdXRoX3RpbWUiOjE1MDY1OTAzMTQsIm5vbmNlIjoiYThlYmU4MGIxOTQyNDBmOGFlMzAxZTJmM2RmOGI0M2QiLCJhdF9oYXNoIjoidU1fSWVKZV9KTjI3UFR0ekMzVXlEdyIsInVzZXJuYW1lIjoiYidkZWFkYmVlZicifQ.PHYIeT9a94vhJaxpxBix8AeM296zfOHiTHBo5977xk3ggUGhhqKQIzNz7T1dEEmDmFRb3rWSbl6oxblegNxke4VkzuqNOfA7l7xAzQ6XcMVVOqTMAIxLdDex9LgFD7yIX1yvMo2pwQx8AuSy8eNiJAjEGXYm9sIrijTSQpfVThM

Payload:

{
  "iss": "https://eid.local/api/openid",
  "sub": "1",
  "aud": "123456",
  "exp": 1506590915,
  "iat": 1506590315,
  "auth_time": 1506590314,
  "nonce": "a8ebe80b194240f8ae301e2f3df8b43d",
  "at_hash": "uM_IeJe_JN27PTtzC3UyDw",
  "username": "b'deadbeef'"
}

Solves #62.

BenjaminKeller commented 6 years ago

@zervnet @nils-wisiol @MrM0nkey This PR is ready for review.

auvin commented 6 years ago

I think github has some rendering problems because it shows a commit, which does not exist anymore. As a rebase was already done and i don't know how to solve this in another way, i will close this PR and create a duplicate. See #84