Line data Source code
1 : #region Copyright
2 : // // -----------------------------------------------------------------------
3 : // // <copyright company="Chinchilla Software Limited">
4 : // // Copyright Chinchilla Software Limited. All rights reserved.
5 : // // </copyright>
6 : // // -----------------------------------------------------------------------
7 : #endregion
8 :
9 : using System;
10 : using System.Collections.Generic;
11 : using System.Linq;
12 : using System.Net;
13 : using System.Net.Http;
14 : using System.Net.Http.Headers;
15 : using System.Web.Http;
16 : using cdmdotnet.Logging;
17 : using Cqrs.Authentication;
18 : using Cqrs.Services;
19 : using System.Net.Http.Formatting;
20 : using System.Web;
21 : using Cqrs.Configuration;
22 :
23 : namespace Cqrs.WebApi
24 : {
25 : /// <summary>
26 : /// A <see cref="ApiController"/> that expects the <see cref="ISingleSignOnToken.Token"/> to be sent as a <see cref="HttpHeaders"/> with a key whose name is defined by the <see cref="System.Configuration.ConfigurationManager.AppSettings"/> "Cqrs.Web.AuthenticationTokenName", in accordance with OAuth specifications
27 : /// </summary>
28 : /// <remarks>
29 : /// See https://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/creating-api-help-pages for details on adding WebApi Help Pages.
30 : /// </remarks>
31 : public abstract class CqrsApiController
32 : : ApiController
33 : {
34 : /// <summary>
35 : /// Instantiates a new instance of <see cref="CqrsApiController"/>.
36 : /// </summary>
37 2 : protected CqrsApiController(ILogger logger, ICorrelationIdHelper correlationIdHelper, IConfigurationManager configurationManager)
38 : {
39 : CorrelationIdHelper = correlationIdHelper;
40 : ConfigurationManager = configurationManager;
41 : Logger = logger;
42 : }
43 :
44 : /// <summary>
45 : /// Gets or set the <see cref="ICorrelationIdHelper"/>.
46 : /// </summary>
47 : protected ICorrelationIdHelper CorrelationIdHelper { get; private set; }
48 :
49 : /// <summary>
50 : /// Gets or set the <see cref="ILogger"/>.
51 : /// </summary>
52 : protected ILogger Logger { get; private set; }
53 :
54 : /// <summary>
55 : /// Gets or set the <see cref="IConfigurationManager"/>.
56 : /// </summary>
57 : protected IConfigurationManager ConfigurationManager { get; private set; }
58 :
59 : /// <summary>
60 : /// Extracts the authentication token looking for a <see cref="KeyValuePair{TKey,TValue}"/> where the key as defined by the <see cref="System.Configuration.ConfigurationManager.AppSettings"/> "Cqrs.Web.AuthenticationTokenName",
61 : /// from the <see cref="HttpRequest.Headers"/>, if one isn't found we then try the <see cref="HttpRequest.Cookies"/>
62 : /// </summary>
63 2 : protected virtual string GetToken()
64 : {
65 : string authenticationTokenName = ConfigurationManager.GetSetting("Cqrs.Web.AuthenticationTokenName") ?? "X-Token";
66 :
67 : string xToken = null;
68 : IEnumerable<string> tokenValue;
69 : if (Request.Headers.TryGetValues(authenticationTokenName, out tokenValue))
70 : xToken = tokenValue.First();
71 : else
72 : {
73 : CookieHeaderValue cookie = Request.Headers.GetCookies(authenticationTokenName).FirstOrDefault();
74 : if (cookie != null)
75 : xToken = cookie[authenticationTokenName].Value;
76 : }
77 :
78 : return xToken;
79 : }
80 :
81 : /// <summary>
82 : /// Create a <see cref="IServiceRequest{TAuthenticationToken}"/> setting header information.
83 : /// </summary>
84 2 : protected virtual IServiceRequest<TSingleSignOnToken> CreateRequest<TSingleSignOnToken>()
85 : where TSingleSignOnToken : ISingleSignOnToken, new()
86 : {
87 : return new ServiceRequest<TSingleSignOnToken>
88 : {
89 : AuthenticationToken = CreateAuthenticationToken<TSingleSignOnToken>(),
90 : CorrelationId = CorrelationIdHelper.GetCorrelationId()
91 : };
92 : }
93 :
94 : /// <summary>
95 : /// Create a <see cref="IServiceRequestWithData{TAuthenticationToken,TData}"/> setting header information.
96 : /// If <paramref name="createParameterDelegate"/> is not null, it is used to populate <see cref="IServiceRequestWithData{TAuthenticationToken,TData}.Data"/> otherwise <see cref="CreateParameter{TParameters}"/> is used.
97 : /// </summary>
98 2 : protected virtual IServiceRequestWithData<TSingleSignOnToken, TParameters> CreateRequestWithData<TSingleSignOnToken, TParameters>(Func<TParameters> createParameterDelegate = null)
99 : where TSingleSignOnToken : ISingleSignOnToken, new()
100 : where TParameters : new()
101 : {
102 : return new ServiceRequestWithData<TSingleSignOnToken, TParameters>
103 : {
104 : AuthenticationToken = CreateAuthenticationToken<TSingleSignOnToken>(),
105 : CorrelationId = CorrelationIdHelper.GetCorrelationId(),
106 : Data = createParameterDelegate == null ? CreateParameter<TParameters>() : createParameterDelegate()
107 : };
108 : }
109 :
110 : /// <summary>
111 : /// Create an <typeparamref name="TSingleSignOnToken"/>.
112 : /// </summary>
113 : /// <typeparam name="TSingleSignOnToken">Th <see cref="Type"/> of <see cref="ISingleSignOnToken"/>.</typeparam>
114 2 : protected virtual TSingleSignOnToken CreateAuthenticationToken<TSingleSignOnToken>()
115 : where TSingleSignOnToken : ISingleSignOnToken, new()
116 : {
117 : return new TSingleSignOnToken
118 : {
119 : DateIssued = GetDateTokenIssued(),
120 : Token = GetToken(),
121 : TimeOfExpiry = GetTokenTimeOfExpiry()
122 : };
123 : }
124 :
125 : /// <summary>
126 : /// Creates a blank <typeparamref name="TParameters"/>
127 : /// </summary>
128 2 : protected virtual TParameters CreateParameter<TParameters>()
129 : where TParameters : new()
130 : {
131 : return new TParameters();
132 : }
133 :
134 : /// <summary>
135 : /// Get the <see cref="DateTime"/> the current authentication token was issued.
136 : /// </summary>
137 : /// <returns>default(DateTime)</returns>
138 2 : protected virtual DateTime GetDateTokenIssued()
139 : {
140 : return default(DateTime);
141 : }
142 :
143 : /// <summary>
144 : /// Get the <see cref="DateTime"/> the current authentication token will expire.
145 : /// </summary>
146 : /// <returns>default(DateTime)</returns>
147 2 : protected virtual DateTime GetTokenTimeOfExpiry()
148 : {
149 : return default(DateTime);
150 : }
151 :
152 : /// <summary>
153 : /// Completes the provided <paramref name="response"/> by setting the appropriate <see cref="HttpResponseMessage.StatusCode"/> and populating <see cref="HttpResponseMessage.Content"/> with <paramref name="serviceResponse"/>.
154 : /// </summary>
155 2 : protected virtual HttpResponseMessage CompleteResponse<TServiceResponse>(HttpResponseMessage response, TServiceResponse serviceResponse)
156 : where TServiceResponse : IServiceResponse
157 : {
158 : serviceResponse.CorrelationId = CorrelationIdHelper.GetCorrelationId();
159 :
160 : HttpConfiguration configuration = Request.GetConfiguration();
161 : var contentNegotiator = configuration.Services.GetContentNegotiator();
162 : ContentNegotiationResult negotiationResult = contentNegotiator.Negotiate(typeof(IServiceResponse), Request, configuration.Formatters);
163 :
164 : response.Content = new ObjectContent<IServiceResponse>(serviceResponse, negotiationResult.Formatter, negotiationResult.MediaType);
165 :
166 : switch (serviceResponse.State)
167 : {
168 : case ServiceResponseStateType.Succeeded:
169 : response.StatusCode = HttpStatusCode.Accepted;
170 : break;
171 : case ServiceResponseStateType.FailedAuthentication:
172 : response.StatusCode = HttpStatusCode.Forbidden;
173 : break;
174 : case ServiceResponseStateType.FailedAuthorisation:
175 : response.StatusCode = HttpStatusCode.Unauthorized;
176 : break;
177 : case ServiceResponseStateType.FailedValidation:
178 : response.StatusCode = HttpStatusCode.PreconditionFailed;
179 : break;
180 : case ServiceResponseStateType.FailedWithAFatalException:
181 : response.StatusCode = HttpStatusCode.InternalServerError;
182 : break;
183 : case ServiceResponseStateType.FailedWithAnUnexpectedException:
184 : response.StatusCode = HttpStatusCode.InternalServerError;
185 : break;
186 : case ServiceResponseStateType.Unknown:
187 : response.StatusCode = HttpStatusCode.BadRequest;
188 : break;
189 : default:
190 : response.StatusCode = HttpStatusCode.Ambiguous;
191 : break;
192 : }
193 :
194 : return response;
195 : }
196 :
197 : /// <summary>
198 : /// Creates a new <see cref="HttpResponseMessage"/> and completes the response by setting the appropriate <see cref="HttpResponseMessage.StatusCode"/> and populating <see cref="HttpResponseMessage.Content"/> with <paramref name="serviceResponse"/>.
199 : /// </summary>
200 2 : protected virtual HttpResponseMessage CompleteResponse<TServiceResponse>(TServiceResponse serviceResponse)
201 : where TServiceResponse : IServiceResponse
202 : {
203 : var response = new HttpResponseMessage();
204 :
205 : return CompleteResponse(response, serviceResponse);
206 : }
207 :
208 : /// <summary>
209 : /// Creates a new <see cref="HttpResponseMessage"/> and completes the response by setting the appropriate <see cref="HttpResponseMessage.StatusCode"/> and populating <see cref="HttpResponseMessage.Content"/> with <paramref name="serviceResponse"/>.
210 : /// </summary>
211 2 : protected virtual HttpResponseMessage<TServiceResponse> CompleteResponseWithData<TServiceResponse>(TServiceResponse serviceResponse)
212 : where TServiceResponse : IServiceResponse
213 : {
214 : var response = new HttpResponseMessage<TServiceResponse>();
215 :
216 : CompleteResponse(response, serviceResponse);
217 :
218 : return response;
219 : }
220 : }
221 :
222 : /// <summary>
223 : /// A <see cref="ApiController"/> that expects the <see cref="ISingleSignOnToken.Token"/> to be sent as a <see cref="HttpHeaders"/> with a key of "X-Token", in accordance with OAuth specifications
224 : /// </summary>
225 : /// <remarks>
226 : /// See https://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/creating-api-help-pages for details on adding WebApi Help Pages.
227 : /// </remarks>
228 : public abstract class CqrsApiController<TAuthenticationToken>
229 : : CqrsApiController
230 2 : {
231 : /// <summary>
232 : /// Instantiates a new instance of <see cref="CqrsApiController"/>.
233 : /// </summary>
234 2 : protected CqrsApiController(ILogger logger, ICorrelationIdHelper correlationIdHelper, IConfigurationManager configurationManager, IAuthenticationTokenHelper<TAuthenticationToken> authenticationTokenHelper)
235 : : base(logger, correlationIdHelper, configurationManager)
236 : {
237 : AuthenticationTokenHelper = authenticationTokenHelper;
238 : }
239 :
240 : /// <summary>
241 : /// Gets or set the <see cref="IAuthenticationTokenHelper{TAuthenticationToken}"/>.
242 : /// </summary>
243 : protected IAuthenticationTokenHelper<TAuthenticationToken> AuthenticationTokenHelper { get; private set; }
244 :
245 : /// <summary>
246 : /// Reads the current authentication token for the request from <see cref="AuthenticationTokenHelper"/>.
247 : /// </summary>
248 2 : protected override string GetToken()
249 : {
250 : TAuthenticationToken token = AuthenticationTokenHelper.GetAuthenticationToken();
251 : if (token != null)
252 : return token.ToString();
253 : return null;
254 : }
255 :
256 : /// <summary>
257 : /// Create a <see cref="IServiceRequest{TAuthenticationToken}"/> setting header information.
258 : /// </summary>
259 2 : protected virtual IServiceRequest<TAuthenticationToken> CreateRequest()
260 : {
261 : TAuthenticationToken token = AuthenticationTokenHelper.GetAuthenticationToken();
262 : return new ServiceRequest<TAuthenticationToken>
263 : {
264 : AuthenticationToken = token,
265 : CorrelationId = CorrelationIdHelper.GetCorrelationId()
266 : };
267 : }
268 :
269 : /// <summary>
270 : /// Create a <see cref="IServiceRequestWithData{TAuthenticationToken,TData}"/> setting header information.
271 : /// If <paramref name="createParameterDelegate"/> is not null, it is used to populate <see cref="IServiceRequestWithData{TAuthenticationToken,TData}.Data"/> otherwise <see cref="CqrsApiController.CreateParameter{TParameters}"/> is used.
272 : /// </summary>
273 2 : protected virtual IServiceRequestWithData<TAuthenticationToken, TParameters> CreateRequestWithData<TParameters>(Func<TParameters> createParameterDelegate = null)
274 : where TParameters : new()
275 : {
276 : TAuthenticationToken token = AuthenticationTokenHelper.GetAuthenticationToken();
277 : return new ServiceRequestWithData<TAuthenticationToken, TParameters>
278 : {
279 : AuthenticationToken = token,
280 : CorrelationId = CorrelationIdHelper.GetCorrelationId(),
281 : Data = createParameterDelegate == null ? CreateParameter<TParameters>() : createParameterDelegate()
282 : };
283 : }
284 : }
285 : }
|