Skip to content

Get Storage Access

Introduction

The preparation for creating an account in the AOS is minimal. It is only required that you are already registered in an AAI that is supported by the GfBio SSO Service, i.e. DFN AAI, Life Science Login (ELIXIR AAI) or GfBio Accounts. These are also the current options that are offered if you want to register or login via the official AOS demo website. If you want to register via the AOS API instead, you just have to put the OIDC token you received from one of the previously mentioned services into the user registration request header for authorization.

To create/modify resources within the given scope/permissions you have to generate API token(s) after you have been activated by an AOS instance administrator.

Please note that these following tutorials cover only the most basic operations but we do our best to make the as extensive as possible. For a complete list of the public API endpoints, their matching requests and responses, please refer to our Aruna Object Storage REST API Swagger-UI.

Client Creation

If you plan to send your requests through gRPC the first step is to open a connection to the gRPC gateway of the server you want to send the requests to.

The presence of a client connection to the specific resource service is required for all further requests in this tutorial if the requests are send via gRPC.

Danger

These are minimal reproducible examples only for demonstration purposes which should not be used 'as-is' in a production environment!

To use the Rust API library you have to set it as dependency aruna-rust-api = "<Aruna-Rust-API-Version>" in the cargo.toml of your project.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
use aruna_rust_api::api::aruna::api::storage::services::v1::{
    storage_info_service_client,
    user_service_client,
    project_service_client,
    collection_service_client,
    object_service_client,
    object_group_service_client,
}
use std::sync::Arc;
use tonic::codegen::InterceptedService;
use tonic::metadata::{AsciiMetadataKey, AsciiMetadataValue};
use tonic::transport::{Channel, ClientTlsConfig};

// Create a client interceptor which always adds the specified api token to the request header
#[derive(Clone)]
pub struct ClientInterceptor {
    api_token: String,
}
// Implement a request interceptor which always adds 
//  the authorization header with a specific API token to all requests
impl tonic::service::Interceptor for ClientInterceptor {
    fn call(&mut self, request: tonic::Request<()>) -> Result<tonic::Request<()>, tonic::Status> {
        let mut mut_req: tonic::Request<()> = request;
        let metadata = mut_req.metadata_mut();
        metadata.append(
            AsciiMetadataKey::from_bytes("authorization".as_bytes()).unwrap(),
            AsciiMetadataValue::try_from(format!("Bearer {}", self.api_token.as_str())).unwrap(),
        );

        return Ok(mut_req);
    }
}

fn main() {
    // Create connection to AOS instance gRPC gateway
    let api_token   = "MySecretArunaApiToken".to_string();
    let tls_config  = ClientTlsConfig::new();
    let endpoint    = Channel::from_shared("https://<URL-To-AOS-Instance-gRPC-Gateway>").unwrap().tls_config(tls_config).unwrap();
    let channel     = endpoint.connect().await.unwrap();
    let interceptor = ClientInterceptor { api_token: api_token.clone() };

    // Create the individual client services
    let mut info_client         = storage_info_service_client::StorageInfoServiceClient::new(channel.clone());
    let mut user_client         = user_service_client::UserServiceClient::with_interceptor(channel.clone(), interceptor.clone());
    let mut project_client      = project_service_client::ProjectServiceClient::with_interceptor(channel.clone(), interceptor.clone());
    let mut collection_client   = collection_service_client::CollectionServiceClient::with_interceptor(channel.clone(), interceptor.clone());
    let mut object_client       = object_service_client::ObjectServiceClient::with_interceptor(channel.clone(), interceptor.clone());
    let mut object_group_client = object_group_service_client::ObjectGroupServiceClient::with_interceptor(channel.clone(), interceptor.clone());

    // Do something with the client services ...
}

To use the Python API library in your Python project you have to install the PyPI package: pip install Aruna-Python-API.

Note

This example additionally implements an interceptor which adds the authorization token automatically to each request send by the service clients.

It is a little more complicated and extra work up front but offers the advantage of having to worry less about the correct API token request metadata later.

All Python examples in this documentation assume that the client services have been initialized with an interceptor.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import collections
import grpc

from aruna.api.storage.services.v1.collection_service_pb2_grpc import CollectionServiceStub
from aruna.api.storage.services.v1.object_service_pb2_grpc import ObjectServiceStub
from aruna.api.storage.services.v1.objectgroup_service_pb2_grpc import ObjectGroupServiceStub
from aruna.api.storage.services.v1.project_service_pb2_grpc import ProjectServiceStub
from aruna.api.storage.services.v1.info_service_pb2_grpc import StorageInfoServiceStub
from aruna.api.storage.services.v1.user_service_pb2_grpc import UserServiceStub

# Valid Aruna API token
#   In a production environment this should be stored in a more secure location ...
API_TOKEN = 'MySecretArunaApiToken'

# AOS instance gRPC gateway endpoint
AOS_HOST = '<URL-To-AOS-Instance-gRPC-Gateway>' # Protocol (e.g. https://) has to be omitted
AOS_PORT = '443'


class _MyAuthInterceptor(grpc.UnaryUnaryClientInterceptor):
    """
    Implement abstract class grpc.UnaryUnaryClientInterceptor to extend request metadata.
    """
    def intercept_unary_unary(self, continuation, client_call_details, request):
        # Append authorization token to request metadata
        metadata = []
        if client_call_details.metadata is not None:
           metadata = list(client_call_details.metadata)
        metadata.append(('authorization', f'Bearer {API_TOKEN}'))

        # Continue with new client call details
        request_iterator = iter((request,))
        updated_details = _ClientCallDetails(
            client_call_details.method, client_call_details.timeout, 
            metadata, client_call_details.credentials
        )

        return continuation(updated_details, next(request_iterator))


class _ClientCallDetails(
        collections.namedtuple(
            '_ClientCallDetails',
            ('method', 'timeout', 'metadata', 'credentials')),
        grpc.ClientCallDetails):
    """
    Implement grpc.ClientCallDetails to pass modified request details in interceptor.
    """
    pass


class AosClient(object):
    """
     Class to contain the AOS gRPC client service stubs for easier usage.
    """
    def __init__(self, ):
        ssl_credentials = grpc.ssl_channel_credentials()
        self.secure_channel = grpc.secure_channel("{}:{}".format(AOS_HOST, AOS_PORT), ssl_credentials)
        self.intercept_channel = grpc.intercept_channel(self.secure_channel, _MyAuthInterceptor())

        self.info_client = StorageInfoServiceStub(self.secure_channnel)
        self.user_client = UserServiceStub(self.intercept_channel)
        self.project_client = ProjectServiceStub(self.intercept_channel)
        self.collection_client = CollectionServiceStub(self.intercept_channel)
        self.object_client = ObjectServiceStub(self.intercept_channel)
        self.object_group_client = ObjectGroupServiceStub(self.intercept_channel)


# Entry point of the script
if __name__ == '__main__':
    # Instantiate AosClient
    client = AosClient()

    # Do something with the client services ...

To use the Python API library in your Python project you have to install the PyPI package: pip install Aruna-Python-API.

Note

This example does not consider adding the authorization token metadata to every request.

In this case you have to manually add the authorization token header by using the with_call(...) extension of the client service methods.

All Python examples in this documentation assume that the client services have been initialized with an interceptor.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import grpc

from aruna.api.storage.services.v1.collection_service_pb2_grpc import CollectionServiceStub
from aruna.api.storage.services.v1.object_service_pb2_grpc import ObjectServiceStub
from aruna.api.storage.services.v1.objectgroup_service_pb2_grpc import ObjectGroupServiceStub
from aruna.api.storage.services.v1.project_service_pb2_grpc import ProjectServiceStub
from aruna.api.storage.services.v1.info_service_pb2_grpc import StorageInfoServiceStub
from aruna.api.storage.services.v1.user_service_pb2_grpc import UserServiceStub

# Valid Aruna API token
#   In a production environment this should be stored in a more secure location ...
API_TOKEN = 'MySecretArunaApiToken'

# AOS instance gRPC gateway endpoint
AOS_HOST = '<URL-To-AOS-Instance-gRPC-Gateway>' # Protocol (e.g. https://) has to be omitted
AOS_PORT = '443'


class AosClient(object):
    """
    Class to contain the AOS gRPC client service stubs for easier usage.
    """
    def __init__(self):
        # Read TLS credentials from local trusted certificates and instantiate a channel
        ssl_credentials = grpc.ssl_channel_credentials()
        self.channel    = grpc.secure_channel("{}:{}".format(AOS_HOST, AOS_PORT), ssl_credentials)

        self.info_client = StorageInfoServiceStub(self.channnel)
        self.user_client = UserServiceStub(self.channel)
        self.project_client = ProjectServiceStub(self.channel)
        self.collection_client = CollectionServiceStub(self.channel)
        self.object_client = ObjectServiceStub(self.channel)
        self.object_group_client = ObjectGroupServiceStub(self.channel)


# Entry point of the Python script
if __name__ == '__main__':
    # Instantiate AosClient
    client = AosClient()

    # Do something with the client services ...

User registration

Users can register themselves with an individual display name in an AOS instance with their valid OIDC token received from the AAI login.

The email and project parameters are optional. If you provide an e-mail address during registration, you will receive system-relevant notifications to this address e.g. advance notifications of maintenance. The project parameter is a hint for the administrators to associate the newly registered user with a project for identification purposes.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Native JSON request to register OIDC user
curl -d '
  {
    "display_name": "Forename Surname",
    "email": "forename.surname@example.com", 
    "project": "Random Project"
  }' \
     -H "Authorization: Bearer <OIDC_TOKEN>" \
     -H "Content-Type: application/json" \
     -X POST https://<URL-to-AOS-instance-API-gateway>/v1/auth/register
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// Create tonic/ArunaAPI request to register OIDC user
let register_request = RegisterUserRequest {
    display_name: "Forename Surname".to_string(),
    email: "forename.surname@example.com".to_string(),
    project: "Random Project".to_string(),
};

// Send the request to the AOS instance gRPC gateway
let response = user_client.register_user(register_request)
                          .await
                          .unwrap()
                          .into_inner();

// Do something with the response
println!("Registered user: {:#?}", response.user_id)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# Create tonic/ArunaAPI request to register OIDC user
request = RegisterUserRequest(
    display_name="Forename Surname",
    email="forename.surname@example.com",
    project="Random Project"
)

# Send the request to the AOS instance gRPC gateway
response = client.user_client.RegisterUser(
    request=request,
    metadata=(('authorization', f'Bearer {OIDC_TOKEN}'),)
)

# Do something with the response
print(f'{response}')

User activation

Note

Users can only be activated by AOS instance administrators.

After registration users additionally have to be activated in a second step.

1
2
3
4
# For convenience, administrators can request info on all unactivated users at once
curl -H "Authorization: Bearer <API-Or-OIDC_TOKEN>" \
     -H "Content-Type: application/json" \
     -X GET https://<URL-to-AOS-instance-API-gateway>/v1/user/not_activated
1
2
3
4
# Native JSON request to activate registered user
curl -H "Authorization: Bearer <API-Or-OIDC_TOKEN>" \
     -H "Content-Type: application/json" \
     -X PATCH https://<URL-to-AOS-instance-API-gateway>/v1/user/<user-id>/activate
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// Create tonic/ArunaAPI request to fetch all not activated users
let get_request = GetNotActivatedUsersRequest {};

// Send the request to the AOS instance gRPC gateway
let unactivated = user_client.get_not_activated_users(request)
                             .await
                             .unwrap()
                             .into_inner();

// Do something with the response
println!("{:#?}", unactivated);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// Create tonic/ArunaAPI request for user activation
let user_id = uuid::Uuid::parse("12345678-1234-1234-1234-123456789999").unwrap();

let activate_request = ActivateUserRequest {
    user_id: user_id.to_string()
};

// Send the request to the AOS instance gRPC gateway
let activate_response = user_client.activate_user(activate_request)
                                   .await
                                   .unwrap()
                                   .into_inner();

// Do something with the response
println!("Activated user: {:#?}", activate_response.user_id)
1
2
3
4
5
6
7
8
# Create tonic/ArunaAPI request to fetch all not activated users
request = GetNotActivatedUsersRequest()

# Send the request to the AOS instance gRPC gateway
response = client.user_client.GetNotActivatedUsers(request=request)

# Do something with the response
print(f'{response}')
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Create tonic/ArunaAPI request for user activation
request = ActivateUserRequest(
    user_id="<user-id>"  # Has to be a valid UUID v4 of a registered user
)

# Send the request to the AOS instance gRPC gateway
response = client.user_client.ActivateUser(request=request)

# Do something with the response
print(f'{response}')

Who Am I / What Am I

To check which user a token is associated with or get information about the current users permissions, you can use the UserService API.

Note

Only AOS instance administrators can request user information of other users.

1
2
3
4
# Native JSON request to fetch user information associated with authorization token
curl -H "Authorization: Bearer <API-Or-OIDC_TOKEN>" \
     -H "Content-Type: application/json" \
     -X GET https://<URL-to-AOS-instance-API-gateway>/v1/user
1
2
3
4
# Native JSON request to fetch user information associated with the provided user id
curl -H "Authorization: Bearer <API-Or-OIDC_TOKEN>" \
     -H "Content-Type: application/json" \
     -X GET https://<URL-to-AOS-instance-API-gateway>/v1/user?userId=<user-id>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// Create tonic/ArunaAPI request to fetch user info of current user
let get_request = GetUserRequest {
    user_id: "".to_string()
};

// Send the request to the AOS instance gRPC gateway
let response = user_client.get_user(get_request)
                          .await
                          .unwrap()
                          .into_inner();

// Do something with the response
println!("Received permission info for user: {:#?}", response.user);
println!("Received project permissions:");
for permission in response.project_permissions {
    println!("{:#?}", permission);
}
1
2
3
4
5
6
7
8
# Create tonic/ArunaAPI request to fetch user info of current user
request = GetUserRequest()

# Send the request to the AOS instance gRPC gateway
response = client.user_client.GetUser(request=request)

# Do something with the response
print(f'{response}')