@@ -114,6 +114,12 @@ pub struct Info {
114
114
#[ derive( Clone , Debug , Deserialize , Serialize , PartialEq ) ]
115
115
pub struct Url ( #[ serde( with = "url_serde" ) ] url:: Url ) ;
116
116
117
+ impl Url {
118
+ pub fn parse < S : AsRef < str > > ( input : S ) -> std:: result:: Result < Url , url:: ParseError > {
119
+ url:: Url :: parse ( input. as_ref ( ) ) . map ( Url )
120
+ }
121
+ }
122
+
117
123
/// Contact information for the exposed API.
118
124
///
119
125
/// See <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#contactObject>.
@@ -420,7 +426,7 @@ enum ParameterStyle {
420
426
#[ derive( Clone , Debug , Deserialize , Serialize , PartialEq , Default ) ]
421
427
pub struct Schema {
422
428
/// [JSON reference](https://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03)
423
- /// path to another defintion
429
+ /// path to another definition
424
430
#[ serde( skip_serializing_if = "Option::is_none" ) ]
425
431
#[ serde( rename = "$ref" ) ]
426
432
pub ref_path : Option < String > ,
@@ -848,24 +854,80 @@ pub enum SecurityScheme {
848
854
#[ serde( rename = "bearerFormat" ) ]
849
855
bearer_format : String ,
850
856
} ,
851
- // FIXME: Implement
852
- // #[serde(rename = "oauth2")]
853
- // Oauth2 {
854
- // flow: String,
855
- // #[serde(rename = "authorizationUrl")]
856
- // authorization_url: String,
857
- // #[serde(rename = "tokenUrl")]
858
- // #[serde(skip_serializing_if = "Option::is_none")]
859
- // token_url: Option<String>,
860
- // scopes: BTreeMap<String, String>,
861
- // },
857
+ #[ serde( rename = "oauth2" ) ]
858
+ OAuth2 { flows : Flows } ,
862
859
#[ serde( rename = "openIdConnect" ) ]
863
860
OpenIdConnect {
864
861
#[ serde( rename = "openIdConnectUrl" ) ]
865
862
open_id_connect_url : String ,
866
863
} ,
867
864
}
868
865
866
+ /// Allows configuration of the supported OAuth Flows.
867
+ /// See [link]
868
+ /// [link][https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#oauth-flows-object]
869
+ #[ derive( Clone , Debug , Deserialize , Serialize , PartialEq ) ]
870
+ #[ serde( rename_all = "camelCase" ) ]
871
+ pub struct Flows {
872
+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
873
+ pub implicit : Option < ImplicitFlow > ,
874
+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
875
+ pub password : Option < PasswordFlow > ,
876
+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
877
+ pub client_credentials : Option < ClientCredentialsFlow > ,
878
+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
879
+ pub authorization_code : Option < AuthorizationCodeFlow > ,
880
+ }
881
+
882
+ /// Configuration details for a implicit OAuth Flow
883
+ /// See [link]
884
+ /// [link](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#oauth-flow-object)
885
+ #[ derive( Clone , Debug , Deserialize , Serialize , PartialEq ) ]
886
+ #[ serde( rename_all = "camelCase" ) ]
887
+ pub struct ImplicitFlow {
888
+ pub authorization_url : Url ,
889
+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
890
+ pub refresh_url : Option < Url > ,
891
+ pub scopes : BTreeMap < String , String > ,
892
+ }
893
+
894
+ /// Configuration details for a password OAuth Flow
895
+ /// See [link]
896
+ /// [link](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#oauth-flow-object
897
+ #[ derive( Clone , Debug , Deserialize , Serialize , PartialEq ) ]
898
+ #[ serde( rename_all = "camelCase" ) ]
899
+ pub struct PasswordFlow {
900
+ token_url : Url ,
901
+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
902
+ pub refresh_url : Option < Url > ,
903
+ pub scopes : BTreeMap < String , String > ,
904
+ }
905
+
906
+ /// Configuration details for a client credentials OAuth Flow
907
+ /// See [link]
908
+ /// [link](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#oauth-flow-object
909
+ #[ derive( Clone , Debug , Deserialize , Serialize , PartialEq ) ]
910
+ #[ serde( rename_all = "camelCase" ) ]
911
+ pub struct ClientCredentialsFlow {
912
+ token_url : Url ,
913
+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
914
+ pub refresh_url : Option < Url > ,
915
+ pub scopes : BTreeMap < String , String > ,
916
+ }
917
+
918
+ /// Configuration details for a authorization code OAuth Flow
919
+ /// See [link]
920
+ /// [link](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#oauth-flow-object
921
+ #[ derive( Clone , Debug , Deserialize , Serialize , PartialEq ) ]
922
+ #[ serde( rename_all = "camelCase" ) ]
923
+ pub struct AuthorizationCodeFlow {
924
+ pub authorization_url : Url ,
925
+ token_url : Url ,
926
+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
927
+ pub refresh_url : Option < Url > ,
928
+ pub scopes : BTreeMap < String , String > ,
929
+ }
930
+
869
931
// TODO: Implement
870
932
/// A map of possible out-of band callbacks related to the parent operation. Each value in
871
933
/// the map is a Path Item Object that describes a set of requests that may be initiated by
@@ -922,3 +984,59 @@ pub struct ExternalDoc {
922
984
pub description : Option < String > ,
923
985
// TODO: Add "Specification Extensions" https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#specificationExtensions}
924
986
}
987
+
988
+ #[ cfg( test) ]
989
+ mod tests {
990
+ use super :: * ;
991
+
992
+ #[ test]
993
+ fn test_security_scheme_oauth_deser ( ) {
994
+ const IMPLICIT_OAUTH2_SAMPLE : & str = r#"{
995
+ "type": "oauth2",
996
+ "flows": {
997
+ "implicit": {
998
+ "authorizationUrl": "https://example.com/api/oauth/dialog",
999
+ "scopes": {
1000
+ "write:pets": "modify pets in your account",
1001
+ "read:pets": "read your pets"
1002
+ }
1003
+ },
1004
+ "authorizationCode": {
1005
+ "authorizationUrl": "https://example.com/api/oauth/dialog",
1006
+ "tokenUrl": "https://example.com/api/oauth/token",
1007
+ "scopes": {
1008
+ "write:pets": "modify pets in your account",
1009
+ "read:pets": "read your pets"
1010
+ }
1011
+ }
1012
+ }
1013
+ }"# ;
1014
+ let obj: SecurityScheme = serde_json:: from_str ( & IMPLICIT_OAUTH2_SAMPLE ) . unwrap ( ) ;
1015
+ match obj {
1016
+ SecurityScheme :: OAuth2 { flows } => {
1017
+ assert ! ( flows. implicit. is_some( ) ) ;
1018
+ let implicit = flows. implicit . unwrap ( ) ;
1019
+ assert_eq ! (
1020
+ implicit. authorization_url,
1021
+ Url :: parse( "https://example.com/api/oauth/dialog" ) . unwrap( )
1022
+ ) ;
1023
+ assert ! ( implicit. scopes. contains_key( "write:pets" ) ) ;
1024
+ assert ! ( implicit. scopes. contains_key( "read:pets" ) ) ;
1025
+
1026
+ assert ! ( flows. authorization_code. is_some( ) ) ;
1027
+ let auth_code = flows. authorization_code . unwrap ( ) ;
1028
+ assert_eq ! (
1029
+ auth_code. authorization_url,
1030
+ Url :: parse( "https://example.com/api/oauth/dialog" ) . unwrap( )
1031
+ ) ;
1032
+ assert_eq ! (
1033
+ auth_code. token_url,
1034
+ Url :: parse( "https://example.com/api/oauth/token" ) . unwrap( )
1035
+ ) ;
1036
+ assert ! ( implicit. scopes. contains_key( "write:pets" ) ) ;
1037
+ assert ! ( implicit. scopes. contains_key( "read:pets" ) ) ;
1038
+ }
1039
+ _ => assert ! ( false , "wrong security scheme type" ) ,
1040
+ }
1041
+ }
1042
+ }
0 commit comments