Diese Version (2017/10/27 13:20) ist ein Entwurf.Überprüfungen: 0/1
Dies ist eine alte Version des Dokuments!
App/Service Development
Description
You have a new service (Webapplication, mobile app, desktop application, …) and you would like using either our AAI (Authentication and Authorization Infrastructure) or access to one of our APIs (Application Progammable Interface) or both. We provide both - a SAML2 infrastructure (Shibboleth) and an OpenID Connect infrastructure.
First thing you need to decide is wether your service should be a Shibboleth service provider or a service using OpenID Connect. If you just want authentication and authorization including attribute releasing in a browser-only environement your probably want SAML2 (Shibboleth), however OpenID Connect is the more modern protocol and you can achieve the same. In the end it is up to you what you would like to implement. As soon as you want more besides just authenticate in a browser-only environement, you will need OpenID Connect since it is the only way to interact with our API services (resource server).
It has to be mentioned that our OpenID Connect IdP is a layer on the top of shibboleth, meaning every OpenID Connect provider is a shibboleth provider as well. But a shibboleth provider is not necessarily an OpenID Connect provider.
Register your app
First thing you're required to do is regsiter your app.
There is no interface yet for self register your app.
Please write a mail to support@gselroth.com with the following information:
- App name
- App description
- App logo (OPTIONAL)
- Protocol (Shibboleth or OpenID Connect) (Usually you want OpenID Connect here)
Shibboleth
If you have choosen Shibboleth for nr. 4, wee need the following additional information:
- URL to your SP (service provider) Metadata
OpenID Connect
If you have choosen OpenID Connect for nr. 4, wee need the following additional information:
- Client authentication method (Usually you want „client_secret_post“ here) (See OpenID-Connect Specification part 9)
- App type (Android app, JavaScript app, desktop app, webserver app, …)
- redirect_uri
Resource server
Following API resource server are available:
| Name | API Version | URL | Typ |
|---|---|---|---|
| IN2 | v1 | https://api.tam.ch | JSON/XML REST |
| CloudFS | v1 | https://cloudfs.tam.ch/api | JSON/XML REST |
Shibboleth
Please continue to OpenId Connect if you work with the OpenID Connect protocol.
Metadata
Our IdP is called https://aai.tam.ch, therefore you can receive the metadata from our IdP (identity provider) via:
https://aai.tam.ch/idp/shibboleth
As mentioned above we need your SP metadata to successfully connect your SP to our IdP.
Attributes
It is possible to release the following attributes, be aware that all attributes with policy „all“ will get released to any shibboleth SP by default. If you require attributes from the policy „strict“ you will need special permission.
| OID | Attribute | Source | Description | Policy |
|---|---|---|---|---|
| - | dn | LDAP:entryDN | LDAP DN | strict |
| 2.16.840.1.113730.3.1.3 | employeeNumber | LDAP:employeeNumber | user id (only unique in each organization) | all |
| 2.5.4.42 | givenName | LDAP:givenName | all | |
| 0.9.2342.19200300.100.1.3 | LDAP:mail | all | ||
| - | memberOf | LDAP:memberOf | group membership | strict |
| 0.9.2342.19200300.100.1.41 | mobile | LDAP:mobile | strict | |
| 2.5.4.10 | o | LDAP:o | Schule | all |
| 2.5.4.11 | ou | LDAP:ou | organization unit | all |
| 2.5.4.3 | sn | LDAP:sn | surname | all |
| 1.3.6.1.4.1.39555.19 | tamBirthday | LDAP:tamBirthday | strict | |
| 1.3.6.1.4.1.39555.17 | tamClassLevel | LDAP:tamClassLevel | ||
| 1.3.6.1.4.1.39555.20 | tamGender | LDAP:tamGender | m, f, m/f | all |
| 1.3.6.1.4.1.39555.16 | tamPrimaryRole | LDAP:tamPrimaryRole | primary group of membership | all |
| 1.3.6.1.4.1.39555.3 | tamUniqueName | LDAP:tamUniqueName | unique username over all organizations [uid].[o] | all |
| 1.3.6.1.4.1.39555.23 | tamUUID | LDAP:tamUUID | truly unique user identifier | all |
| 0.9.2342.19200300.100.1.1 | uid | LDAP:uid | username (only unique in each organization ) | all |
| - | tamClassCommonName | Scripted Attribute | array of class | all |
OpenID Connect
Please go to Shibboleth if you have a shibboleth-only SP.
OpenID Connect is a modern protocol based on OAUTH2 meant for authentication. Please read http://openid.net/connect if you are not familiar with the protocol.
Discovery
Our provider is called https://accounts.tam.ch, therefore you can browse the discovery sheet viahttps://accounts.tam.ch/.well-known/openid-configuration
Attributes
Your can receive the follwing user attributes by query the userinfo endpoint (See discovery) https://accounts.tam.ch/userinfo (Depending which scopes you have requested during requesting the token).
| Attribute | Description | Scope |
|---|---|---|
| dn | LDAP DN | intranet |
| employee_number | user id (only unique in each organization) | intranet |
| given_name | given name | profile |
| name | given name / family name | profile |
| email address | ||
| member_of | group memberships | intranet |
| phone_number | mobile phone number | phone |
| organization | school | intranet |
| organization_unit | organization unit | intranet |
| family_name | surname | profile |
| birthday | birthdate | profile |
| tam_class_level | class level | intranet |
| gender | m, f, m/f | profile |
| tam_primary_role | primary group of membership | intranet |
| preferred_username | unique username over all organizations [uid].[o] | profile |
| tam_uuid | truly unique user identifier | intranet |
| uid | username (only unique in each organization ) | intranet |
Authorization Code Flow
Use the authorization code flow for applications in which you can store the client_secret secretly.
The authorization code flow consists roughly of the following steps:
- Send authentication request to the authentication endpoint
- Let end-user authenticate at the authorization server
- Receive authorization code
- Send token request to the token endpoint using the authorization code
- Receive id token and access token
Authentication Request
To send an authentication request to the authentication endpoint (See discovery) https://accounts.tam.ch/auth you need to submit the following query parameters:
| Parameter | Values | Description |
|---|---|---|
| response_type | code | The response type, for auth code flow you need the value „code“ |
| client_id | client_id | Your client_id which you have received during registering your app |
| redirect_uri | URI | The redirect_uri which you submitted during registering your app |
| scope | openid profile email intranet offline_access | Scopes to query, you should always request openid and profile. Note: If you want to query an intranet2 API you are required to request the scope intranet as well. |
| state | Random String | Random string to prevent cross-site-request-forgery attacks. |
Example authentication request:
https://accounts.tam.ch/auth?redirect_uri=https%3A%2F%2Fcloudfs.tam.ch&scope=openid%20offline_access&client_id=my_client_id&response_type=code
If all parameters were valid, you receive an authentication response containing a code parameter. Its value is the authorization code.
Example authentication response:
https://cloudfs.tam.ch?state=3189f4685e2da677f86210b0f8f32451b5ac8c97de7097216542dde6d122e4fb.e44cf97d799330c8497996ead02edece&code=sJi902gBBCGG_icj0pOnFoQDL_o0Pju9RNXEjGGL9-Y
Access Token Request
To receive an access token you need to send a HTTP POST token request with the authorization code from the authentication response to the token endpoint (See discovery) https://accounts.tam.ch/token. You need to submit the following POST parameters:
| Parameter | Values | Description |
|---|---|---|
| grant_type | authorization_code | For the authorization code flow the value „authorization_code“ is needed here |
| redirect_uri | The redirect_uri of your app | |
| code | authorization code received in the authentication response | |
| client_id | The client_id you have received during registering your app (If you registered your app for the client_secret_post authentication method) | |
| client_secret | The client_secret you have received during registering your app (If you registered your app for the client_secret_post authentication method) |
Additionally you have to authenticate the token request using the client authentication method you submitted during the registration of your app.
Example token request:
https://accounts.tam.ch/token with POST parameters grant_type=authorization_code&code=sJi902gBBcGG_icj0pOnFoQDL_o0Pju9RNXEjGGL9-Y&redirect_uri=https%3A%2F%2Fcloudfs.tam.ch&client_id=my_client_id&client_secret=my_client_secret
If you have choosen client_secret_basic as client authentication method during app registration your are required to send the client credentials in the basic scheme along the token POST request instead attaching them as POST parameters:
Authorization: Basic base64(my_client_id:my_client_secret)
The response from the authentication server contains a JSON document containing the access_token, the token_type, the refresh_token (If you requested the scope offline_access), the time until the token expires (expires_in) and the id token (JWT).
Example token response (JSON Body):
{
"access_token": "MsPh6Igqrfw98XYMqaAfbhTB2s79_iyovt7aBiF0bvo",
"token_type": "Bearer",
"refresh_token": "d1KQFvE-29SO-Es8lPbYhBCXDT2dpWANaKZmE3lBI9A",
"expires_in": 3600,
"id_token": "eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOlwvXC9hY2NvdW50c2Rldi50YW0uY2hcL29wLmp3ayIsImtpZCI6ImFjY291bnRzZGV2LnRhbS5jaF8wMFMifQ.eyJpc3MiOiJodHRwczpcL1wvYWNjb3VudHNkZXYudGFtLmNoIiwic3ViIjoiMzAzMTMwMzEzMDMxMzAzMTMwMzEzMDMxMzAzMTMwMzExZThjOTkwZGRjY2VlZjBlMGVjOWUzN2Q1M2FiMThlYzgxYTIzN2Y3ZGM2YjRlOTgxYWQ2MDA0MzljMjcxMmI3IiwiYXVkIjpbImxvY2FsLXRlc3QtYXBwIl0sImV4cCI6MTUwNDE4MzA0NSwiaWF0IjoxNTA0MTgyNzQ1LCJhdF9oYXNoIjoicktCQWM0S0hlU3B4ekdEY2xRMGlfQSJ9.u4NUGCZ0uRoIXWeOQiQJ9EXgXC7qL205wUXeS-Vk5nXBhS62xoZ-pFH_-PUGhz5zbDTQpw49QqzgLmlOXSZocFdfNi1xsPlbDmTX0CPhMSZKGJ3jXKV0ciJL7joLwwK7Y3vZLsOuVLLzkFA9zEKsFN1bBrsWWcKisvLtd96CBGk6ClRZ8RhmVHWVTOJsaIAKxL4uH4LDtx9046s-9DVYpiJJsRd36YjbNCMGPi8ddY3OP-3Mhw0XErzlN8BuxcmzzWpt01kke9eqI2Gd_aA-JDP671nw6DQwiuQkPwTnvZheTOTZehg1BplWTbE3lGXyOjPix2xAMB-viffCFRsSaQ"
}
With the access_token you have received above you can now query an API (resource server).
Refresh Access Token
With the refresh_token you have received you can get a new access_token.
You only get a refresh token if you have requested the scope offline_access.
To receive a new set of tokens you need to send a token request with the refresh_token to the token endpoint (See discovery) https://accounts.tam.ch/token. You need to submit the following query parameters:
| Parameter | Values | Description |
|---|---|---|
| grant_type | refresh_token | To receive a new set of tokens the value „refresh_token“ is needed here |
| refresh_token | refresh_token received in the token response | |
| client_id | The client_id you have received during registering your app | |
| client_secret | The client_secret you have received during registering your app |
As for the access token request you have to authenticate the refresh request using the client authentication method you submitted during the registration of your app.
Example token request:
https://accounts.tam.ch/token with POST parameters grant_type=refresh_token&refresh_token=d1KQFvE-29SO-Es8lPbYhBCXDT2dpWANaKZmE3lBI9A and HTTP header Authorization: Basic base64(my_client_id:my_client_secret) (for client authentication method client_secret_basic)
The response from the authentication server is the same as for the token request above except that it might not contain an id_token.
Implicit Grant
Use the implicit grant for applications which can not store a client_secret secretly. A good example of such an application is a web SPA (Single page application).
Authentication Request
You need to send a request to the authorization endpoiont (See discovery) https://accounts.tam.ch/auth. You need to submit the following query parameters:
| Parameter | Values | Description |
|---|---|---|
| response_type | id_token token | The response type, for implicit auth you need „id_token“ or „id_token token“ |
| client_id | client_id | Your client_id which you have received during registering your app |
| redirect_uri | URI | The redirect_uri which you submitted during registering your app |
| scope | openid profile email intranet | Scopes to query, you should always request openid and profile. Note: If you want to query an intranet2 API you are required to request the scope intranet as well. |
| state | Random String | Random string to prevent cross-site-request-forgery attacks. |
| nonce | Random String | Random string to catch replay attacks. |
Example token request:
https://accounts.tam.ch/token?response_type=id_token token&state=551ffbec-40ea-43b0-bb7d-4e509615be55&redirect_uri=https://cloudfs.tam.ch&client_id=my_client_id&scope=openid&nonce=t8+mAHzTW8jGDVjesgxu65HsJFoMdv
If you have a valid shibboleth session, you will get forwarded to your redirect_uri, all parameters from the authorization server are attached after a hashtag (#). If you do not have a valid shibboleth session you will first forwarded to https://aai.tam.ch to authenticate with shibboleth.
Example of a successful response from the authorization server:
https://cloudfs.tam.ch#?access_token=x1D3XM04-xc1avB6cLR8Cco5nCTo-pdc6MDcZHovzII&token_type=Bearer&expires_in=3600&id_token=eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOlwvXC9hY2NvdW50c2Rldi50YW0uY2hcL29wLmp3ayIsImtpZCI6ImFjY291bnRzZGV2LnRhbS5jaF8wMFMifQ.eyJpc3MiOiJodHRwczpcL1wvYWNjb3VudHNkZXYudGFtLmNoIiwic3ViIjoiMzAzMTMwMzEzMDMxMzAzMTMwMzEzMDMxMzAzMTMwMzFjNzhlMmY1ODI0NjMyNWVkYjUxMWE4Zjc5YTA1ZjkxYjFiYmEzMDgwNjQ4ZmY3MWJhY2U4NTgwNjEyNTM2ZDE3YTVlMzlkNGQwOWUzOTU5MTZhYmQxMDQwNTExNDAwMTcwMDQ5NWI4M2ViNGFhYjFjNWMyNzMyN2Y1ZWYzYjQxZSIsImF1ZCI6WyJsb2NhbC10ZXN0LWFwcCJdLCJleHAiOjE1MDQxMDI0ODYsImlhdCI6MTUwNDEwMjE4Niwibm9uY2UiOiJhYmNkIiwiYXRfaGFzaCI6Im00RTlDWk9uVVpzRmdrcjRqdjctdncifQ.SdS_hcmfcyqUJYhY7h3h7vu7g8gEzORxscdIr4dulAI2cBy7p2am0Lm8zH4p42ajseRwWC9MSTPeTXobLsGAYlLRxEqd1CT5FsVdrCcR6OXH4FtAX3qtXSm1Sna_1E700hMeY9wQ20caSjARYArnsZWMyt7oGnwqA6wHeKJr8bz3gk44vL8cT_wRxrPQumRd0nqx28VFEhrvP2gRa_EWml5bg-cjNqYKYQCbGi8g6bJDuDYju2U0GelwuQEctm8Hbs9xBqNN1uXaBQlO4KIPMhpL_roU0ERxSgaCyS5WBOaxRI8ffwTjKqq5BejokJhCSLfYQo6ILtDDPG8t2qn1ww&state=551ffbec-40ea-43b0-bb7d-4e509615be55
With the access_token you have received above you can now query an API (resource server).
Note that access tokens which are created during implicit auth will expire after 3600s, therefore you are required to the same request for an access_token above again.
JavaScript code example
This code example provides an insight how to authenticate with your AAI and get an access token to query a resource server (CloudFS):
Note that this is not an example for a production use case!
var client = {
OAUTH2_CLIENT_ID: 'xxxxxxxxxxxxxxxxxxxxxxxx',
OAUTH2_REDIRECT_URI: 'https://myapp.example.org',
OAUTH2_AUTH_SERVER: 'https://accounts.tam.ch/token',
OAUTH2_SCOPE: 'openid profile',
CLOUDFS_API:'https://cloudfs.tam.ch/api',
CLOUDFS_API_VERSION: 1,
access_token: null,
/**
* Initialize client()
*/
init: function() { this.checkAuth(); },
/**
* Extract Token from URI
*/
extractToken: function(hash) {
var match = hash.match(/access_token=(\w+)/);
return !!match && match[1];
},
/**
* Check Access Token
*/
checkAuth: function() {
this.access_token = this.extractToken(window.location.hash);
var options = {
type:'GET',
url: client.CLOUDFS_API+'/api/auth',
statusCode: {
401: function() {
client.initOauth2();
},
403: function() {
client.initOauth2();
},
400: function() {
client.callCloudfsApi();
}
}
}
if(client.access_token != '') {
options.headers = { "Authorization": 'Bearer '+client.access_token, }
}
$.ajax(options);
},
/**
* Forward to tam OAuth2 Authorization Server
*/
initOauth2: function() {
var nonce = ''(Math.random()*1e32).toString(36);''
window.location.href = client.OAUTH2_AUTH_SERVER+'/cloudfs?response_type=token&client_id='+
client.OAUTH2_CLIENT_ID+'&nonce='+nonce+'&redirect_uri='+client.OAUTH2_REDIRECT_URI+'&scope='+<font inherit/inherit;;black;;inherit>encodeURIComponent(</font>client.OAUTH2_SCOPE);
},
/**
* Make an API call to CLOUDFS_API
*/
callCloudfsApi: function() {
$.ajax({
url: client.CLOUDFS_API+'/v'+client.CLOUDFS_API_VERSION+'/children',
type: 'GET', dataType: 'json',
statusCode: {
200: function(data) {
console.log(data);
},
401: function() {
client.initOauth2();
}
},
headers = { "Authorization": 'Bearer '+client.access_token, }
});
}
}
Introspection
An endpoint for token introspection is available at https://accounts.tam.ch/introspect (See discovery). The introspection endpoint can be queried with an access_token to check if the token is valid (e.g. for resource servers to verify the token of a user).
| Parameter | Values | Description |
|---|---|---|
| token | access_token | The access token you want to introspect |
Example introspection request:
https://accounts.tam.ch/introspect?token=d-7Amc_P7nyCE25PEcgGEAacff93xAKKianxzFG3TUu
If the token is valid (it exists and is not expired), you receive a JSON document containing some information about the token. In every case the json document contains a key „active“ with a boolean value indicating the validity of the token.
Example introspection response:
active true scopes "openid offline_access" client_id my_client_id username tamUniqueName token_type "bearer" exp "1504616611" iat "1504528113" sub "30313031303130313031303130313031a07275a794dd6feb6b60a5cce43caed2e732b458093495ff08b04eddda32e78911a76e8d47fc079093caba846aa4ff7d" aud 0 my_client_id iss "https://accounts.tam.ch"
Revocation
An endpoint for token revocation is available at https://accounts.tam.ch/revoke (See discovery). The revocation endpoint can be queried with an access_token or a refresh_token to revoke this token.
| Parameter | Values | Description |
|---|---|---|
| token | your_token | The token (access_token or refresh_token) you want to revoke |
Additionally you have to authenticate the token request using the client authentication method you submitted during the registration of your app.
Example revocation request:
https://accounts.tam.ch/revoke?token=d-7Amc_P7nyCE25PEcgGEAacff93xAKKianxzFG3TUu&client_id=my_client_id&client_secret=my_client_secret
If the client credentials were valid, the server responds with a HTTP status 200, meaning the token is revoked.
