1+ // Copyright (c) 2021-2024 Estonian Information System Authority
2+ //
3+ // Permission is hereby granted, free of charge, to any person obtaining a copy of
4+ // this software and associated documentation files (the "Software"), to deal in
5+ // the Software without restriction, including without limitation the rights to
6+ // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7+ // the Software, and to permit persons to whom the Software is furnished to do so,
8+ // subject to the following conditions:
9+ //
10+ // The above copyright notice and this permission notice shall be included in all
11+ // copies or substantial portions of the Software.
12+ //
13+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15+ // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16+ // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17+ // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18+ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19+
20+ namespace WebEid . AspNetCore . Example . Controllers . Api
21+ {
22+ using System ;
23+ using System . Text ;
24+ using Microsoft . AspNetCore . Mvc ;
25+ using Microsoft . Extensions . Options ;
26+ using System . Text . Json ;
27+ using System . Text . Json . Serialization ;
28+ using WebEid . AspNetCore . Example . Options ;
29+ using WebEid . Security . Challenge ;
30+
31+ [ ApiController ]
32+ [ Route ( "auth/mobile" ) ]
33+ public class MobileAuthController : ControllerBase
34+ {
35+ private const string WebEidMobileAuthPath = "auth" ;
36+ private const string MobileLoginPath = "/auth/mobile/login" ;
37+
38+ private readonly IChallengeNonceGenerator nonceGenerator ;
39+ private readonly WebEidMobileOptions mobileOptions ;
40+
41+ public MobileAuthController (
42+ IChallengeNonceGenerator nonceGenerator ,
43+ IOptions < WebEidMobileOptions > mobileOptions )
44+ {
45+ this . nonceGenerator = nonceGenerator ;
46+ this . mobileOptions = mobileOptions . Value ;
47+ }
48+
49+ [ HttpPost ( "init" ) ]
50+ public IActionResult Init ( )
51+ {
52+ var challenge = nonceGenerator . GenerateAndStoreNonce ( TimeSpan . FromMinutes ( 5 ) ) ;
53+ var challengeBase64 = challenge . Base64EncodedNonce ;
54+
55+ var loginUri = $ "{ Request . Scheme } ://{ Request . Host } { MobileLoginPath } ";
56+
57+ var payload = new AuthPayload (
58+ challengeBase64 ,
59+ loginUri ,
60+ mobileOptions . RequestSigningCert ? true : null
61+ ) ;
62+
63+ var json = JsonSerializer . Serialize ( payload ) ;
64+ var encodedPayload = Convert . ToBase64String ( Encoding . UTF8 . GetBytes ( json ) ) ;
65+
66+ var authUri = BuildAuthUri ( encodedPayload ) ;
67+
68+ return Ok ( new AuthUri ( authUri ) ) ;
69+ }
70+
71+ private string BuildAuthUri ( string encodedPayload )
72+ {
73+ var baseUri = mobileOptions . BaseRequestUri ;
74+
75+ if ( baseUri . StartsWith ( "http" , StringComparison . OrdinalIgnoreCase ) )
76+ {
77+ return $ "{ baseUri . TrimEnd ( '/' ) } /{ WebEidMobileAuthPath } #{ encodedPayload } ";
78+ }
79+
80+ return $ "{ baseUri } { WebEidMobileAuthPath } #{ encodedPayload } ";
81+ }
82+
83+ public record AuthPayload (
84+ [ property: JsonPropertyName ( "challenge" ) ] string Challenge ,
85+ [ property: JsonPropertyName ( "login_uri" ) ] string LoginUri ,
86+ [ property: JsonPropertyName ( "get_signing_certificate" ) ] bool ? GetSigningCertificate
87+ ) ;
88+
89+ public record AuthUri (
90+ [ property: JsonPropertyName ( "auth_uri" ) ] string AuthUriValue
91+ ) ;
92+ }
93+ }
0 commit comments