2009-12-22

Web services API design suggestion ???

Trước khi chuẩn bị design một web services API langxang đã đọc và tham khảo rất nhiều resources trên net. Mục đích muốn focus vào RESTful hơn là SOAP nhưng vấn đề nan giải nhất là security. Mới thử một suggestion nhưng vẫn còn nhiều chuyện phải nghĩ ... nói chung chẳng có gì hoàn hảo cả, chắc phải nghĩ vậy thôi.

Mình đã từng đọc đâu đó trên InfoQ câu này
REST is simple. Applying Enterprise-class Security is not.

1. Giới thiệu

Web services và format support

Tạo một bộ RESTful web services hỗ trợ XML và JSON qua HTTP.

Cơ chế authenticate và authorization

Các yếu tố cần suy nghĩ đến là user experience UX[1], OpenID support (federate-authentication) cũng như resources trong thời điểm hiện tại.
Yêu cầu đặt ra là một cơ chế flexible, lightweight. Tất nhiên không thể tốt hoàn toàn nhưng cần đạt mức chấp nhận được (về security, thời gian thực hiện ...).
Suggestion là một mô hình dạng token signing lấy ý tưởng từ Flickr API (thay vì dùng OAuth). Trong thời gian tới sẽ cố gắng hoàn thiện hệ thống API, có thể thực hiện support OAuth trong thời gian tới.

Các thành phần cần thực hiện

  1. Thiết kế và định nghĩa các APIs.
  2. Server viết bằng PHP thực hiện các chức năng: đăng ký API key, xử lý authenticate, xử lý authorization và RESTful request.
  3. Library C# SDK wrap các API
  4. Library PHP SDK wrap các API (optional)
2. Cơ chế authenticate và authorization (tham khảo Flickr Authentication API[3])

Authentication prerequisites

Tất cả các ứng dụng muốn sự dụng Authenticate API phải đăng ký một API key (đáp ứng yêu cầu có thể monitor ứng dụng) và phải thiết lập các thông số sau để có thể có API key
  1. Application title
  2. Application description
  3. Application logo graphic (optional)
  4. Application ’about’ URL (for example application introduction and download, optional)

Authentication methods

Sau khi đăng ký API key, ứng dụng sẽ được cung cấp secret key dùng trong quá trình signing (signing request process). Ứng dụng sẽ chọn 1 trong 2 methods chứng thực – web based hoặc non-web based.
Hiện tại sẽ support dạng non-web based authentication. Tương lai sẽ mở rộng hỗ trợ 3 loại như sau: web based authentication, non-web base authentication và mobile authentication.

3. Authentication dành cho non-web based application

Hiện tại Flickr sử dụng message digest algorithms MD5[7] theo đó desktop và non-web based application sẽ thực hiện giao tiếp với server để nhận được token. Tuy nhiên với những hạn chế của message digest algorithms MD5 có thể phải thay đổi so với cách thực hiện của Flickr[4] [5] [6]. Chi tiết xem phần signing process.
Đầu tiên desktop application thực hiện gọi API method auth.getFrob, method này yêu cầu signing (xem phần thực hiện signing). Nếu thành công method sẽ response một ‘frob’, dùng để construct một URL cho phép user thực hiện đăng nhập (launch system’s default browser) http://www.company.com/services/auth/?api_key=[api_key]&perms=[perms]&frob=[frob]&api_sig=[api_sig]
API signature là kết quả của signing process.
Permission yêu cầu user thực hiện grant, đối với trường hợp hiện tại chúng ta có thể omit. Đối với user log in vào system sẽ thực hiện cấp quyền tương ứng với user đó (yêu cầu làm rõ chức năng và cách xử lý của server).
Như vậy URL thực hiện authenticate là:
http://www.company.com/services/auth/?api_key=[api_key]&frob=[frob]&api_sig=[api_sig]
Hệ thống sẽ yêu cầu user log in với username/password hay OpenID. Tên application và mô tả của application sẽ được hiển thị (trong trường hợp quyết định permission theo role sau khi đăng nhập không cần hiển thị permissions mà ứng dụng mong muốn có). Nếu user đăng nhập thành công thay vì redirect về callback URL như web application, system sẽ hiển thị thông báo user log in thành công và hướng dẫn quay về application (và có thể close trang thông báo này).
Sau khi user thực hiện chứng thực thành công, quay lại application để báo cho application biết đã xong quá trình chứng thực. Application cần thực hiện gọi API method auth.getToken bằng cách cung cấp api_key và frob (method này yêu cầu signing, xem phần thực hiện signing).
Response sẽ bao gồm authentication token cần thực hiện các API call sau này (các thông tin khác kèm theo ví dụ summary của user profile, yêu cầu làm rõ sau).

Renewing non-web based authentication tokens

Để kiểm tra cần renewing hay có đủ permission hay không, application cần thực hiện gọi auth.checkToken. Nếu token không hợp lệ hoặc không đủ permission, application cần yêu cầu một token mới giống như các bước yêu cầu token đầu tiên.

Implementation guidelines

User profile data (bao gồm auth tokens) nên được lưu lại tại local user's 'profile', theo đó có thể cho phép switch user với cơ chế multiple profiles/users mà không thực hiện sharing auth data. Trong môi trường Windows có thể thực hiện dựa vào registry trong phần HKEY_CURRENT_USER, hay trong user's home directory đối với OSX/Unix.
Users phải được cung cấp chức năng 'logout'.

4. Authentication permissions

Application không nên yêu cầu quyền cao hơn mức cần thiết phải sử dụng. Cụ thể trong trường hợp này không quan tâm đến việc request permissions mà permissions sẽ được cung cấp tùy theo loged in user.
Cụ thể có 3 level cơ bản như sau (xem xét chỉnh sửa nếu cần thiết):
  • read - permission cho phép read private information
  • write - permission cho phép thêm, sửa và xóa metadata (bao gồm permission 'read')
  • delete - permission cho phép delete thông tin (bao gồm 'write' và 'read')

5. Authentication tokens

Mỗi authentication token được chỉ định riêng cho một user và một application tương ứng với application's api key, và chỉ được dùng tương ứng với application key này. Application có thể kiểm tra tình trạng của auth token bằng cách thực hiện API method auth.checkToken, method sẽ return tính hợp lệ của token cùng với user đã thực hiện authenticated (và permissions tương ứng nếu cần).
Authentication tokens có thể được thiết lập thời gian expire bởi user khi user thực hiện chứng thực với hệ thống. Chức năng này là chức năng nâng cao (có thể hide by default), có thể có 2 options là theo hour (1 hour) hoặc never. Chỉ duy nhất một auth token/app/user valid tại bất kỳ thời điểm nào. Application phải có trách nhiệm xử lý khi auth token expired, invalid và thực hiện renew.
Tất cả các API calls sử dụng auth token phải được signed (xem signing process).

6. Authentication frobs

Mỗi authentication frob sẽ tương ứng với một user và một application’s API key và chỉ có thể được sử dụng bởi application có API key này.
Giá trị của application frobs chỉ hợp lệ trong vòng 60 phút kể từ khi được tạo hoặc cho đến khi application thực hiện gọi auth.getToken.
Chỉ một application frob tương ứng với một application và một user được coi là hợp lệ tại bất kỳ thời điểm nào. Application phải có trách nhiệm xử lý khi auth token expired, invalid và thực hiện renew.

7. Signing

Tất cả các API call sử dụng auth token phải được ký tên (signed). Ngoài ra khi thực hiện các method auth.* methods và khi thực hiện chuyển hướng (redirections) tới trang chứng thực của hệ thống (system’s auth page) các yêu cầu này cũng phải thực hiện signing.
Như đã đề cập về hạn chế của message digest algorithms đặc biệt là MD5 hash, quá trình signing sẽ thực hiện khác với Flickr.
Các hướng có thể thực hiện là keep auth token secret bằng SSL, dùng auth token để signing hay coi auth token như là password bằng cách sử dụng HTTP digest authentication (RFC2617).
Một giải pháp khả thi là sử dụng một secure MAC implementations như HMAC-SHA1[8] (được hỗ trợ bởi hầu hết các programming language kể cả client và server side). Key của HMAC-SHA1 có thể sử dụng là shared secret.
Quá trình signing thực hiện theo các bước như sau:
  1. Thực hiện tạo danh sách các đối số thực (argument list) và sắp xếp theo alphabetical order dựa theo tên của tham số parameter name của từng argument. Có thể cần sẽ thực hiện normalize parameter (sẽ hướng dẫn cụ thể tham khảo Amazon Web Service, OAuth)
Ví dụ: foo = 1, bar = 2, baz = 3 sẽ được sắp xếp thành bar = 2, baz = 3, foo = 1
  1. Concatenate shared secret với các cặp argument dạng name/value (argument name/value pairs). Ví dụ: shared secret là BANANA concatenated argument list string là bar=2&baz=3&foo=1. Dùng shared secret BANANA làm key của HMAC. Kết quả có thể có format dạng base64 hoặc hexa string. Ví dụ: kết quả signature với giả sử format là base64 như sau Dcpc3Uf85y1VvZFs276KvGtum5Q=
  2. Append kết quả này vào argument list với parameter name là api_sig
Ví dụ: api_sig= Dcpc3Uf85y1VvZFs276KvGtum5Q=

8. Example cho non-web based application

  1. User nhấn login button trên application
  2. Application gọi background call tới server để nhận frob, call auth.getFrob ví dụ như sau http://www.company.com/services/rest/?method=auth.getFrob&api_key=987654321&api_sig=Dcpc3Uf85y1VvZFs276KvGtum5Q=
  3. System return frob ‘1a2b3c4d5e’
  4. Application launch system’s default browser với URL tạo được từ frob như sau http://www.company.com/services/auth/?api_key=987654321 &frob=1a2b3c4d5e&api_sig= Cdpc3Uf85y1VvZFs276KvGtum5Q=
  5. Nếu user chưa loged in vào web site, user sẽ được hỏi có thực hiện log in hay không.
· User có thể đăng nhập bằng log in form(username/password)
· User có thể chọn đăng nhập bằng OpenID,khi đó sẽ thực hiện theo flow authentication bằng OpenID
  1. Sau khi đăng nhập thành công user sẽ được hỏi có cho phép ứng dụng sử dụng các thông tin private hay không (trong trường hợp ứng dụng cụ thể thì private data là gì cần định nghĩa rõ)
  2. User chọn ‘Yes’ web site sẽ update auth database.
  3. User được hướng dẫn quay lại application và có thể đóng web page.
  4. User quay lại application và nhấn button ‘Continue’ (nút log in button trong bước log in có thể chuyển thành continue button)
  5. Application thực hiện background call tới auth.getToken, ví dụ http://www.company.com/services/rest/?method=auth.getToken&api_key=987654321&frob=1a2b3c4d5e&api_sig= Depc3Uf85y1VvZFs276KvGtum5Q=
  6. System trả về auth token ‘9765984’
  7. Application có thể thực hiện các background API call với auth token (signing với key là shared secret) ví dụ http://www.company.com/services/rest/?method=user.getProfile&api_token= 9765984&api_sig= Efpc3Uf85y1VvZFs276KvGtum5Q=

9. References