development:security
Differences
This shows you the differences between two versions of the page.
| Next revision | Previous revision | ||
| development:security [2016/10/26 13:17] – created chrisknoll | development:security [2018/03/20 13:33] (current) – anthonysena | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| This page describes the details of the security implementation in WebAPI. | This page describes the details of the security implementation in WebAPI. | ||
| - | (Please provide the following details): | + | ===== DEPENDENCIES ===== |
| - | What library/ | + | The security |
| - | What's the difference between resource | + | [[http:// |
| - | Please list the new tables introduced to support the security layer, and provide a short description of each table. | + | It also uses: |
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| - | How is a new user added into the system to grant permissions to? | ||
| - | How are the default permissions assigned? | + | ===== WEBAPI ===== |
| + | ==== SECURITY LAYER ==== | ||
| - | For a developer adding a new service end-point, what annotations/ | + | The '' |
| - | Please | + | The default setting in the WebAPI pom.xml is ''< |
| - | + | ||
| + | ==== PATH-BASED SECURITY ==== | ||
| + | |||
| + | The security subsystem is set up by assigning filters to URLs. Before a method underneath the URL is invoked, filters apply some logic. For example, attempt to authenticate user and check if user has permission required to access the method. | ||
| + | |||
| + | ==== AUTHENTICATION ==== | ||
| + | |||
| + | WebAPI itself does not authenticate users, it delegates authentication to external service - Windows Authentication or OAuth provider. | ||
| + | |||
| + | There is a set of authenticating filters which allows to maintain different authentication providers. If authentication is successful, WebAPI responds with token, which then should be used to sign subsequent requests. The token is sent in '' | ||
| + | |||
| + | To sign request put the token prefixed with '' | ||
| + | |||
| + | Authorization: | ||
| + | |||
| + | The token is [[https:// | ||
| + | |||
| + | Here is a list of endpoints related to authentication: | ||
| + | |||
| + | * ''/ | ||
| + | * ''/ | ||
| + | * ''/ | ||
| + | * ''/ | ||
| + | * ''/ | ||
| + | |||
| + | === OAUTH SETTINGS === | ||
| + | |||
| + | Currently supported OAuth providers are Google and Facebook. | ||
| + | |||
| + | To be able to use API of OAuth service provider you need to obtain API Key and API Secret and put these values into POM file | ||
| + | |||
| + | < | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | |||
| + | ==== ADDING NEW OAUTH PROVIDER ==== | ||
| + | |||
| + | OAuth authentication is handled with [[https:// | ||
| + | |||
| + | To add support of new OAuth service provider into WebAPI, you need to go through following steps. | ||
| + | |||
| + | * Register application and obtain oauth api credentials | ||
| + | * Refer to OAuth service provider’s documentation to register application | ||
| + | * Obtain your API key and secret | ||
| + | * Adjust redirect URL. This is a URL of a WebAPI endpoint which is responsible for processing provider’s response. The relative path of the endpoint is ''/ | ||
| + | * Add oauth endpoint | ||
| + | * Create filter for endpoint. Here is a code example for Facebook: | ||
| + | |||
| + | public class AtlasSecurity extends Security { | ||
| + | ... | ||
| + | @Override | ||
| + | public Map< | ||
| + | Map< | ||
| + | ... | ||
| + | |||
| + | // create client | ||
| + | FacebookClient facebookClient = | ||
| + | new FacebookClient(facebookApiKey, | ||
| + | facebookClient.setScope(" | ||
| + | facebookClient.setFields(" | ||
| + | |||
| + | Config cfg = | ||
| + | new Config( | ||
| + | new Clients( | ||
| + | this.oauthApiCallback | ||
| + | , googleClient | ||
| + | , facebookClient | ||
| + | )); | ||
| + | |||
| + | // create filter | ||
| + | SecurityFilter facebookOauthFilter = new SecurityFilter(); | ||
| + | facebookOauthFilter.setConfig(cfg); | ||
| + | facebookOauthFilter.setClients(" | ||
| + | filters.put(" | ||
| + | ... | ||
| + | |||
| + | return filters; | ||
| + | } | ||
| + | ... | ||
| + | } | ||
| + | |||
| + | * Create endpoint | ||
| + | |||
| + | public class AtlasSecurity extends Security { | ||
| + | ... | ||
| + | |||
| + | @Override | ||
| + | public Map< | ||
| + | return new FilterChainBuilder() | ||
| + | ... | ||
| + | .addOAuthPath("/ | ||
| + | ... | ||
| + | .build(); | ||
| + | } | ||
| + | |||
| + | ... | ||
| + | } | ||
| + | |||
| + | * Define URL in POM file to redirect after authentication is completed | ||
| + | |||
| + | < | ||
| + | |||
| + | If authentication completes successfully, | ||
| + | |||
| + | ==== BASIC SECURITY CONFIGURATION ==== | ||
| + | |||
| + | In the event that you do not have one of the supported OAuth providers available, WebAPI also supports as [[documentation: | ||
| + | |||
| + | ==== AUTHORIZAION ==== | ||
| + | |||
| + | To access protected method, user must have an appropriate permission. WebAPI checks permissions which are built based on method’s URL and HTTP Method of the request. | ||
| + | |||
| + | For example, request | ||
| + | |||
| + | GET: myservice/ | ||
| + | |||
| + | corresponds to permission | ||
| + | |||
| + | myservice: | ||
| + | |||
| + | However, user doesn’t need to have exactly this permission, because SHIRO provides wildcard permissions. It means, that permissions are multilevel and each level may be replaced with a wildcard. Levels are separated by the colon sign and the asterisk sign is used as wildcard character. | ||
| + | |||
| + | For the example above, user may access to resource if he or she has one of the following permissions (assuming | ||
| + | |||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | |||
| + | So that it’s easy to change level of granularity by giving permissions to users for a whole services or just for certain entities or whatever makes sense. | ||
| + | |||
| + | For details on wildcard permissions please refer to https:// | ||
| + | |||
| + | ==== PROTECT WEBAPI METHODS ==== | ||
| + | |||
| + | To protect certain method, assign appropriate filters to its URL. There is a helper FilterChainBuilder class, which simplifies this. All you need is just to call '' | ||
| + | |||
| + | Here is an example of how to protect all methods of '' | ||
| + | |||
| + | public class AtlasSecurity extends Security { | ||
| + | ... | ||
| + | @Override | ||
| + | public Map< | ||
| + | return new FilterChainBuilder() | ||
| + | ... | ||
| + | .addProtectedRestPath("/ | ||
| + | .addProtectedRestPath("/ | ||
| + | ... | ||
| + | .build(); | ||
| + | } | ||
| + | ... | ||
| + | } | ||
| + | |||
| + | Now request to all endpoints which matching these patterns should be signed with bearer token (see AUTHENTICATION section) and requires permissions corresponding to endpoint' | ||
| + | |||
| + | To protect all methods, use pattern which matches all endpoints: | ||
| + | |||
| + | public class AtlasSecurity extends Security { | ||
| + | ... | ||
| + | @Override | ||
| + | public Map< | ||
| + | return new FilterChainBuilder() | ||
| + | ... | ||
| + | .addProtectedRestPath("/ | ||
| + | .build(); | ||
| + | } | ||
| + | ... | ||
| + | } | ||
| + | |||
| + | |||
| + | ==== ACCESS CONTROL ==== | ||
| + | |||
| + | Permissions are not directly assigned to user. Instead, they are grouped into roles and then roles are assigned to user. This makes access control flexible. You may think about it in terms of roles which user plays in your infrastructure. If user's responsobilities were changed, you can move he or she into another role. Or you can add permissions into role if you realized that this role should involve new activities. All you need is just update records in database by calling appropriate WebAPI method. | ||
| + | |||
| + | Here is a list of tables which security subsystem uses to handle access control: | ||
| + | |||
| + | * SEC_USER - stores all registered users | ||
| + | * SEC_USER_ROLE - offers many-to-many relation between users and roles | ||
| + | * SEC_ROLE - stores roles | ||
| + | * SEC_ROLE_PERMISSION - offers many-to-many relation between roles and permissions | ||
| + | * SEC_PERMISSION - stores permissions | ||
| + | |||
| + | ==== ADDING NEW USER ==== | ||
| + | |||
| + | When user logs in firts time, record is created in SEC_USER table. Now user is registered and can be associated with roles. | ||
| + | |||
| + | There are two special roles - '' | ||
| + | |||
| + | One personal role is created for each new user. The name of personal role is the same as user's login. | ||
| + | |||
| + | This role is intended to hold permissions which are specific to certain user. For example, | ||
| + | |||
| + | This workflow works when user creates Concept Set, Cohort or Role. Methods which affect these entities are protected. When entity is created, entity-level permissions required for these methods are created as well and then are assigned to creator' | ||
| + | |||
| + | '' | ||
| + | |||
| + | ==== PREDEFINED ROLES ==== | ||
| + | |||
| + | When WebAPI starts | ||
| + | |||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | |||
| + | Each time when WebAPI starts, it looks for configured sources and creates appropriate permissions and roles. One role is created for each source. Roles are named like '' | ||
| + | |||
| + | ==== SETTINGS ==== | ||
| + | |||
| + | Settings are available through POM file. All settings related to security are prefixed with '' | ||
| + | |||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | |||
| + | ==== SSL CONFIGURATION IN TOMCAT ==== | ||
| + | |||
| + | First you will need to obtain and install a certificate. Here are steps to achive this: | ||
| + | |||
| + | * Generate keystore using '' | ||
| + | |||
| + | keytool -genkey -alias webapi -keyalg RSA -keystore C: | ||
| + | |||
| + | * Generate CSR (Certificate Signing Request) | ||
| + | |||
| + | keytool -certreq -alias webapi -keystore C: | ||
| + | |||
| + | * Now you need to follow instructions of CA (Certification Authority) of your choice to submit your CSR (for example VeriSign) to obtain the SSL certifiate. Alternatively, | ||
| + | |||
| + | * When you obtained certificate from CA, you need to import the CA’s root and intermediate certificates into a Java keystore file before you import the actual SSL certificate. The steps below outline this process for a Windows machine. | ||
| + | |||
| + | === Step 1: Retrieving your Root, Intermediate directly from your SSL certificate: | ||
| + | |||
| + | * Take your SSL certificate with a .cer extension. and double click on it. | ||
| + | * At the certificate popup click on Certification Path. | ||
| + | * {{: | ||
| + | * Under Certification Path you will see a tier of three certificates. | ||
| + | * Top certificate = Root | ||
| + | * Middle certificate = Intermediate | ||
| + | * Bottom certificate = SSL certificate for the common name it was issued to. | ||
| + | * {{: | ||
| + | * **Double click** on the **top certificate Root** in order to bring up its information. | ||
| + | * {{: | ||
| + | * Click **Details.** | ||
| + | * Click **Copy to File...** | ||
| + | * {{: | ||
| + | * The Certificate Export Wizard will popup. Click **Next.** | ||
| + | * {{: | ||
| + | * Select **Base-64 encoded X.509 (.cer).** | ||
| + | * Click **Next.** | ||
| + | * {{: | ||
| + | * On the next screen click **Browse** and specify the filename and path you want to save your Root certificate. Name it whatever you desire. **Example: Root.cer** | ||
| + | * Click **Save.** | ||
| + | * You will be taken back to the previous screen with the location and path of this file specified next to browse. **Click Next.** | ||
| + | * {{: | ||
| + | * Complete the export wizard by clicking **Finish**. | ||
| + | |||
| + | === Step 2: Retrieving your Intermediate CA directly from your SSL certificate | ||
| + | |||
| + | //You will perform the same steps as above in step 1 but with the middle certificate (Intermediate).// | ||
| + | |||
| + | * 1. Go back to your SSL certificate under the **Certification Path** tab and **double click** on the Middle Certificate Intermediate in the tier. | ||
| + | * {{: | ||
| + | * Click Details. | ||
| + | * Click Copy to File… | ||
| + | * {{: | ||
| + | * The Certificate Export Wizard will popup. **Click Next.** | ||
| + | * {{: | ||
| + | * Select **Base-64 encoded X.509 (.cer).** | ||
| + | * Click **Next.** | ||
| + | * {{: | ||
| + | * On the next screen click Browse and specify the filename and path you want to save your Intermediate certificate. Name it whatever you desire. Example: Intermediate.cer | ||
| + | * Click Save. | ||
| + | * You will be taken back to the previous screen with the location and path of this file specified next to browse. Click Next. | ||
| + | * {{: | ||
| + | * Complete the export wizard by clicking Finish. | ||
| + | |||
| + | You should now have three files: | ||
| + | - Your Root Certificate. | ||
| + | - Your Intermediate Certificate. | ||
| + | - Your SSL certificate where both the Root, and Intermediate are derived from. | ||
| + | |||
| + | === Step 3: Step 3: Installing your Root CA, CA Intermediate, | ||
| + | |||
| + | Import the Root Certificate first. | ||
| + | |||
| + | keytool -import -alias root -trustcacerts -file C: | ||
| + | |||
| + | Import the Intermediate CA certificate second. You will specify your own alias for this import. Example: Intermediate. | ||
| + | |||
| + | keytool -import -alias intermediate -trustcacerts -file C: | ||
| + | |||
| + | Lastly, import the actual SSL certificate into the keystore. | ||
| + | |||
| + | keytool -importcert -trustcacerts -alias webapi -file C: | ||
| + | |||
| + | Now you can add SSL connector in Tomcat' | ||
| + | |||
| + | < | ||
| + | port=" | ||
| + | protocol=" | ||
| + | maxThreads=" | ||
| + | scheme=" | ||
| + | secure=" | ||
| + | SSLEnabled=" | ||
| + | keyAlias=" | ||
| + | keystoreFile=" | ||
| + | keystorePass=" | ||
| + | clientAuth=" | ||
| + | sslProtocol=" | ||
| + | |||
| + | [[https:// | ||
| + | |||
| + | ===== ATLAS ===== | ||
| + | |||
| + | ==== ACCESS TO UI ELEMENTS ==== | ||
| + | |||
| + | When user accesses some sections of ATLAS or press some buttons it results in calling WebAPI methods. Some of them are protected and user may not have appropriate permission. In this case error is generated. To prevent this ATLAS shows UI controls based on user’s permissions. | ||
| + | |||
| + | If user tries to access protected section and he or she isn’t authenticated, | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | If user is authenticated but doesn’t have permissions required for the section, the following screen will be shown | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | Also some UI controls (such as buttons, checkboxes, etc.) are disabled if user isn’t permitted for corresponding action. For example, if user isn’t permitted to create cohort, the “New Cohort” button is disabled. | ||
| + | |||
| + | ==== CHECKING USER’S PERMISSIONS ==== | ||
| + | |||
| + | Some UI controls may correspond to set of WebAPI calls. To ensure that enabling this UI control is safe permissions must be checked for all required methods. For example, to update Concept Set ATLAS performs two requests | ||
| + | |||
| + | POST: conceptset/ | ||
| + | POST: conceptset/ | ||
| + | |||
| + | where '' | ||
| + | |||
| + | To address this AuthAPI.js contains set of isPermitted… methods to check all necessary permissions required to perform an atomic (in terms of ATLAS) actions. For the above example it is | ||
| + | |||
| + | isPermittedUpdateConceptset(conceptsetId) | ||
| + | |||
| + | AuthAPI.js also contains '' | ||
| + | |||
| + | Note that these permission checks are performed against information contained in the token itself and it may be outdated at the time of checking. This means, that there is still a chance that ATLAS request will be refused by WebAPI with '' | ||
| + | |||
| + | $.ajax({ | ||
| + | ... | ||
| + | error: authApi.handleAccessDenied, | ||
| + | ... | ||
| + | }); | ||
| + | |||
| + | To update the token use '' | ||
| + | |||
| + | ==== SIGNING REQUESTS TO PROTECTED METHODS ==== | ||
| + | |||
| + | Client application should sign request with access token to be able to call protected methods. This means that '' | ||
| + | |||
| + | In case of JQuery AJAX call it may look like this | ||
| + | |||
| + | $.ajax({ | ||
| + | ... | ||
| + | headers: { | ||
| + | Authorization: | ||
| + | }, | ||
| + | ... | ||
| + | |||
| + | }); | ||
| + | |||
| + | ==== MANAGE ROLES AND PERMISSIONS ==== | ||
| + | |||
| + | Permissions are grouped into roles. Administrator can assign role to user. On ‘Configuration’ page you may find ‘Manage Permissions’ button. It opens ‘Roles’ page. | ||
| + | |||
| + | Note that ‘Configuration’ page available only for members of ‘admin’ role. | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | You may click on certain role to edit it or press ‘New Role’ button to create new role. | ||
| + | |||
| + | Now you're on ' | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | To define permissions for role members, go to ‘Permissions’ tab. | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | Note that users can’t create permissions - all necessary permissions are created automatically. | ||
development/security.1477487869.txt.gz · Last modified: by chrisknoll
