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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
//! # 7. Credentials module
//! Module Identifier: `credentials`
//! Type: Configuration Module
//! The credentials module is used to exchange the credentials token that has to
//! be used by parties for authorization of requests.
//! Every OCPI request is required to contain a credentials token in the
//! HTTP Authorization header.
use crate::{types, CommandsHandler, Context, Cpo, Party, PartyStore, Result, VersionsStore};
use async_trait::async_trait;
#[async_trait]
pub trait CredentialsModule {
type PartyModel: Party;
type RegistrationModel;
/// # 7.2.1. GET Method
/// Retrieves the credentials object to access the server’s platform.
/// The request body is empty, the response contains the credentials
/// object to access the server’s platform.
/// This credentials object also contains extra information about the server
/// such as its business details.
async fn credentials_get(&self, ctx: Context) -> Result<types::Credential>;
/// # 7.2.2. POST Method
/// Provides the server with credentials to access the client’s system.
/// This credentials object also contains extra information about the
/// client such as its business details.
/// A POST initiates the registration process for this endpoint’s version.
/// The server must also fetch the client’s endpoints for this version.
async fn credentials_post(
&self,
ctx: Context,
param: types::Credential,
) -> Result<types::Credential>;
/// # 7.2.3. PUT Method
/// Provides the server with updated credentials to access the client’s system.
/// This credentials object also contains extra information about the
/// client such as its business details.
/// A PUT will switch to the version that contains this credentials endpoint if
/// it’s different from the current version.
/// The server must fetch the client’s endpoints again, even if the version has not changed.
/// If successful, the server must generate a new credentials token for the client and
/// respond with the client’s updated credentials to access the server’s system.
/// The credentials object in the response also contains extra information about the server
/// such as its business details.
/// This method MUST return a
/// `HTTP status code 405: method not allowed`
/// if the client has not been registered yet.
async fn credentials_put(
&self,
ctx: Context,
param: types::Credential,
) -> Result<types::Credential>;
/// # 7.2.4. DELETE Method
/// Informs the server that its credentials to access the client’s system are now
/// invalid and can no longer be used.
/// Both parties must end any automated communication.
/// This is the unregistration process.
/// This method __MUST__ return a HTTP status code
/// 405: method not allowed if the client has not been registered before.
async fn credentials_delete(&self, ctx: Context) -> Result<()>;
}
#[async_trait]
impl<DB, CH, M, Rm> CredentialsModule for Cpo<DB, CH>
where
M: Party + Send + 'static,
Rm: Send + 'static,
CH: CommandsHandler,
DB: PartyStore<PartyModel = M, RegistrationModel = Rm> + VersionsStore + Sync,
{
type PartyModel = M;
type RegistrationModel = Rm;
async fn credentials_get(&self, ctx: Context) -> Result<types::Credential> {
let party = self
.db
.get_authorized(ctx.credentials_token)
.await?
.party()?;
let roles = self.db.get_our_roles().await?;
Ok(types::Credential {
token: party.token_they_use(),
url: self.db.base_url(),
roles,
})
}
/// Provides credentials for the Server to access the Clients system.
/// This is done using the Temporary model.
/// If this the authentication of the provided Credential is succesful
///
/// The provided Credentials will be used to create a new Model.
/// The Credentials for this new Model is what is returned.
async fn credentials_post(
&self,
ctx: Context,
param: types::Credential,
) -> Result<types::Credential> {
let reg = self
.db
.get_authorized(ctx.credentials_token.clone())
.await?
.registration()?;
let version_details = self
.client
.get_endpoints_for_version(
ctx.extend(¶m.token),
param.url.clone(),
types::VersionNumber::V2_2,
)
.await?;
let party = self.db.save_new_party(reg, param, version_details).await?;
let roles = self.db.get_our_roles().await?;
Ok(types::Credential {
token: party.token_they_use(),
url: self.db.base_url(),
roles,
})
}
async fn credentials_put(
&self,
ctx: Context,
param: types::Credential,
) -> Result<types::Credential> {
let party = self
.db
.get_authorized(ctx.credentials_token.clone())
.await?
.party()?;
let version_details = self
.client
.get_endpoints_for_version(
ctx.extend(¶m.token),
param.url.clone(),
types::VersionNumber::V2_2,
)
.await?;
let updated_party = self.db.update_party(party, param, version_details).await?;
let roles = self.db.get_our_roles().await?;
Ok(types::Credential {
token: updated_party.token_they_use(),
url: self.db.base_url(),
// @TODO: Add a Store component that can retreive our own roles.
// For now, dummy hardcode this stuff.
roles,
})
}
async fn credentials_delete(&self, ctx: Context) -> Result<()> {
let party = self
.db
.get_authorized(ctx.credentials_token)
.await?
.party()?;
let id = party.id();
self.db.delete_party(id).await?;
Ok(())
}
}