fxbrit / ticketing-system

ticketing system built using the Spring framework
0 stars 0 forks source link

add turnstiles and relative functionalities #10

Closed fxbrit closed 2 years ago

fxbrit commented 2 years ago

we will need a new service in order to:

riccardomengoli commented 2 years ago

I would do this:

LoginService

TransitService (new)

Service to keep statistics about transits. Turnstiles can work without any internet connection. When a ticket is scanned, its validity is checked (locally). If it's valid then a new transit message will be sent with Kafka to TransitService, which will update its stats. The entity exchanged will have fields like {ticketID, userID, turnstileID, time} We can create one example endpoint like transits per turnstile.

riccardomengoli commented 2 years ago

Kafka messages

kafka

fxbrit commented 2 years ago

I would do this

sounds good

riccardomengoli commented 2 years ago

New table: turnstiles [id, name, public_key] Each turnstile has a pair of asymmetric keys, the public key is registered manually in the table turnstiles New endpoints: GET /turnstile/login -> generates a random number and sends it to the turnstile, saved provisionally in a table like validate POST /turnstile/login -> sends the number encrypted with its private key, if ok then it's authenticated

Actually, let's make it simpler. Turnstiles login is not the focus of our application. Let's use the standard username/password that we know how to use.

fxbrit commented 2 years ago

we could recycle some code from the admin enrollment, allowing only administrators to add new turnstiles with a username (id), psw and maybe even a key that we could use for symmetric encryption of the secret (just to keep it as simple as possible, although not great for security).

riccardomengoli commented 2 years ago

Yes, exactly, I'm currently doing that then I'm off to holidays 😜

riccardomengoli commented 2 years ago

So, to recap what has been done and what is missing.

Done:

═════════════════════════════════════════

Still to be done 🥺:

LoginService

TransitService

riccardomengoli commented 2 years ago

Want to move everything to a new microservice? We can discuss it, it probably is a better solution.

Yeah, I see that you were proposing this solution, so let's do it.

TurnstileService

Since the turnstile generates data for TransitService, it requires:

fxbrit commented 2 years ago

I agree with your above comment, this seems like the best solution. although it's worth noting that this probably requires to start from scratch with #23 as most of the changes in there are treating turnstiles as users.

riccardomengoli commented 2 years ago

Yeah probably. I'm currently working on TurnstileService and it should be ready in a few hours. Then I'll do the remaining endpoints for the other services. I'll let you do Kafka however because you have much more experience 😝

In general, everything should be finished by tomorrow evening. Then we can add tests as you said and that's it.

fxbrit commented 2 years ago

I'll let you do Kafka however because you have much more experience 😝 In general, everything should be finished by tomorrow evening.

k, I'll work on the kafka part tomorrow morning then 🎉

riccardomengoli commented 2 years ago

GET /turnstile/key -> gets the key used to validate the JWS, required role TURNSTILE

Ok so this is wrong because the key is not in the LoginService. But apart from that there is a choice to be made.

The JWT signing key is currently in TravelerService, which receives ticket orders and saves all the complete tickets in its own database. TravelerService uses the signing key to return tickets via GET my/tickets/{ticketID} (QR or string). This key is also necessary for TurnstileService in order to check if the transit is valid (and the ticket is not fake).

Since the project file says:

These devices will interact with the overall system authenticating themselves as embedded systems, in order to get the secret used to check the validity of the JWS and provide transit count information.

We need to provide to TurnstileService this key.

We can:

  1. Create endpoint in TravelerService (seems bad to me)
  2. Use Kafka to request the key to TravelerService
  3. Use Kafka to request the key to a new microservice that only provides secrets
  4. Manually insert into TurnstileService the key (but then it cannot be changed, seems very bad)
  5. Other solutions?

What do you think we should do? @fxbrit

fxbrit commented 2 years ago

Manually insert into TurnstileService the key (but then it cannot be changed, seems very bad)

you mean by declaring it in application.properties? actually I don't hate this idea because:

  1. it's simple
  2. it doesn't require to share the key in plaintext using Kafka, which is terrible for security (edit: HTTPS in production will solve this, non-issue)
fxbrit commented 2 years ago

just to be sure, the only interaction that should be implemented using Kafka is:

  1. QR Code is scanned
  2. Turnstile makes API call to /generateTransit
  3. TurnstileService produces a Kafka message and adds an entry to TransitService

is there any other exchange happening that I missed?

riccardomengoli commented 2 years ago

is there any other exchange happening that I missed?

Nope, that is right. Kafka in TurnstileService to send and Kafka in TransitService to receive.

riccardomengoli commented 2 years ago

I also found out what is a JWS😝

a signed JWT (aka a 'JWS')

fxbrit commented 2 years ago

two tasks left to do, see OP.

fxbrit commented 2 years ago

I think there's a problem with the signature verification, I tried the following steps:

  1. Login as admin

    http -v POST :8081/user/login username=admin password=PassWord123!
  2. Create a turnstile

    http -A bearer -a <admin_token> -v POST :8086/register username=test123turn password=psW1111!
  3. Buy a ticket

    http  -A bearer -a <admin_token> -v POST :8080/shop/1 amount=1 paymentInformations\[creditCardNumber\]=12345678 paymentInformations\[cvv\]=123 paymentInformations\[expirationDate\]='2023-11-11'
  4. Get tickets to take JWS

    http  -A bearer -a <admin_token> GET :8082/my/tickets
  5. Login as turnstile

    http -v POST :8086/login username=test123turn password=psW1111!
  6. Generate a transit

    http -A bearer -a <turnstile_token> -v POST :8086/generateTransit jws=<jws>

I ended up with:

HTTP/1.1 400 Bad Request
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 84
Content-Type: application/json
Expires: 0
Pragma: no-cache
Referrer-Policy: no-referrer
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1 ; mode=block

{
    "errorMessage": "Error during ticket validation: Illegal base64url character: '\"'"
}

meanwhile when checking manually the ticket is valid and properly signed.

riccardomengoli commented 2 years ago

In the last request /generateTransit accepts the JWS as plaintext, the jws= part is what is wrong.

fxbrit commented 2 years ago

yup yup, thx. I have some local changes that accept a DTO instead of a String, I will push them soon.

fxbrit commented 2 years ago

https://github.com/fxbrit/ticketing-system/issues/10#issuecomment-1225784062 could be useful for #21