Skip to content

Commit 49d920b

Browse files
authored
Rework on documentation (#335)
1 parent 7233f8d commit 49d920b

19 files changed

+6472
-737
lines changed

README.md

Lines changed: 89 additions & 720 deletions
Large diffs are not rendered by default.

doc/authentication.md

Lines changed: 310 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,310 @@
1+
# Authentication
2+
3+
This guide covers the authentication options available in nanoFramework WebServer.
4+
5+
## Overview
6+
7+
The WebServer supports three types of authentication that can be applied to controllers and individual methods:
8+
9+
1. **Basic Authentication** - HTTP Basic Auth with username/password
10+
2. **API Key Authentication** - Custom header-based authentication
11+
3. **None** - No authentication required
12+
13+
Authentication can be configured at both the class level (applies to all methods) and method level (overrides class-level settings).
14+
15+
## Basic Authentication
16+
17+
### Default Credentials
18+
19+
```csharp
20+
[Authentication("Basic")]
21+
public class SecureController
22+
{
23+
[Route("secure/data")]
24+
public void GetSecureData(WebServerEventArgs e)
25+
{
26+
WebServer.OutPutStream(e.Context.Response, "Secure data");
27+
}
28+
}
29+
30+
// Server setup with default credentials
31+
using (WebServer server = new WebServer(80, HttpProtocol.Http, new Type[] { typeof(SecureController) }))
32+
{
33+
server.Credential = new NetworkCredential("admin", "password");
34+
server.Start();
35+
Thread.Sleep(Timeout.Infinite);
36+
}
37+
```
38+
39+
### Custom Credentials
40+
41+
```csharp
42+
public class UserController
43+
{
44+
[Route("admin")]
45+
[Authentication("Basic:admin secretpassword")]
46+
public void AdminPanel(WebServerEventArgs e)
47+
{
48+
WebServer.OutPutStream(e.Context.Response, "Admin panel");
49+
}
50+
51+
[Route("user")]
52+
[Authentication("Basic:user userpass")]
53+
public void UserPanel(WebServerEventArgs e)
54+
{
55+
WebServer.OutPutStream(e.Context.Response, "User panel");
56+
}
57+
}
58+
```
59+
60+
**Note**: The username cannot contain spaces. Use the format: `"Basic:username password"`
61+
62+
## API Key Authentication
63+
64+
### Default API Key
65+
66+
```csharp
67+
[Authentication("ApiKey")]
68+
public class ApiController
69+
{
70+
[Route("api/data")]
71+
public void GetData(WebServerEventArgs e)
72+
{
73+
WebServer.OutPutStream(e.Context.Response, "API data");
74+
}
75+
}
76+
77+
// Server setup with default API key
78+
using (WebServer server = new WebServer(80, HttpProtocol.Http, new Type[] { typeof(ApiController) }))
79+
{
80+
server.ApiKey = "MySecretApiKey123";
81+
server.Start();
82+
Thread.Sleep(Timeout.Infinite);
83+
}
84+
```
85+
86+
### Custom API Key
87+
88+
```csharp
89+
public class ServiceController
90+
{
91+
[Route("service/premium")]
92+
[Authentication("ApiKey:premium-key-789")]
93+
public void PremiumService(WebServerEventArgs e)
94+
{
95+
WebServer.OutPutStream(e.Context.Response, "Premium service");
96+
}
97+
98+
[Route("service/basic")]
99+
[Authentication("ApiKey:basic-key-456")]
100+
public void BasicService(WebServerEventArgs e)
101+
{
102+
WebServer.OutPutStream(e.Context.Response, "Basic service");
103+
}
104+
}
105+
```
106+
107+
### API Key Usage
108+
109+
Clients must include the API key in the request headers:
110+
111+
```http
112+
GET /api/data HTTP/1.1
113+
Host: 192.168.1.100
114+
ApiKey: MySecretApiKey123
115+
```
116+
117+
**Note**: The header name `ApiKey` is case-sensitive.
118+
119+
## No Authentication
120+
121+
```csharp
122+
[Authentication("None")]
123+
public class PublicController
124+
{
125+
[Route("public/info")]
126+
public void GetPublicInfo(WebServerEventArgs e)
127+
{
128+
WebServer.OutPutStream(e.Context.Response, "Public information");
129+
}
130+
}
131+
```
132+
133+
## Mixed Authentication Example
134+
135+
```csharp
136+
[Authentication("Basic")] // Default for all methods in this class
137+
public class MixedController
138+
{
139+
[Route("secure/basic")]
140+
public void BasicAuth(WebServerEventArgs e)
141+
{
142+
// Uses class-level Basic authentication
143+
WebServer.OutPutStream(e.Context.Response, "Basic auth data");
144+
}
145+
146+
[Route("secure/api")]
147+
[Authentication("ApiKey:special-key-123")] // Override with API key
148+
public void ApiKeyAuth(WebServerEventArgs e)
149+
{
150+
WebServer.OutPutStream(e.Context.Response, "API key data");
151+
}
152+
153+
[Route("secure/custom")]
154+
[Authentication("Basic:customuser custompass")] // Override with custom basic auth
155+
public void CustomAuth(WebServerEventArgs e)
156+
{
157+
WebServer.OutPutStream(e.Context.Response, "Custom auth data");
158+
}
159+
160+
[Route("public")]
161+
[Authentication("None")] // Override to allow public access
162+
public void PublicAccess(WebServerEventArgs e)
163+
{
164+
WebServer.OutPutStream(e.Context.Response, "Public data");
165+
}
166+
}
167+
```
168+
169+
## Multiple Authentication for Same Route
170+
171+
The WebServer supports multiple authentication methods for the same route by creating separate methods:
172+
173+
```csharp
174+
public class MultiAuthController
175+
{
176+
[Route("data")]
177+
[Authentication("Basic")]
178+
public void DataBasicAuth(WebServerEventArgs e)
179+
{
180+
WebServer.OutPutStream(e.Context.Response, "Data via Basic auth");
181+
}
182+
183+
[Route("data")]
184+
[Authentication("ApiKey:key1")]
185+
public void DataApiKey1(WebServerEventArgs e)
186+
{
187+
WebServer.OutPutStream(e.Context.Response, "Data via API key 1");
188+
}
189+
190+
[Route("data")]
191+
[Authentication("ApiKey:key2")]
192+
public void DataApiKey2(WebServerEventArgs e)
193+
{
194+
WebServer.OutPutStream(e.Context.Response, "Data via API key 2");
195+
}
196+
197+
[Route("data")]
198+
public void DataPublic(WebServerEventArgs e)
199+
{
200+
WebServer.OutPutStream(e.Context.Response, "Public data");
201+
}
202+
}
203+
```
204+
205+
## Authentication Flow
206+
207+
The server selects the route for a request using this logic:
208+
209+
1. **No matching methods**: Returns 404 (Not Found)
210+
2. **Authentication provided in request headers**:
211+
- Finds methods requiring authentication
212+
- If credentials match: Calls the matching method
213+
- If credentials don't match: Returns 401 (Unauthorized)
214+
3. **No authentication provided**:
215+
- If a public method exists (no auth required): Calls that method
216+
- If only auth-required methods exist: Returns 401 (Unauthorized)
217+
- For Basic auth methods: Includes `WWW-Authenticate` header
218+
219+
## Server Configuration
220+
221+
```csharp
222+
using (WebServer server = new WebServer(80, HttpProtocol.Http, new Type[] { typeof(MyController) }))
223+
{
224+
// Set default credentials for Basic authentication
225+
server.Credential = new NetworkCredential("defaultuser", "defaultpass");
226+
227+
// Set default API key
228+
server.ApiKey = "DefaultApiKey123";
229+
230+
server.Start();
231+
Thread.Sleep(Timeout.Infinite);
232+
}
233+
```
234+
235+
## Security Best Practices
236+
237+
1. **Use HTTPS**: Always use HTTPS in production to protect credentials
238+
2. **Strong Credentials**: Use strong passwords and API keys
239+
3. **Rotate Keys**: Regularly rotate API keys and passwords
240+
4. **Principle of Least Privilege**: Grant minimal necessary access
241+
5. **Secure Storage**: Avoid hardcoding credentials in source code
242+
243+
## HTTPS with Authentication
244+
245+
```csharp
246+
// Load certificate
247+
X509Certificate2 cert = new X509Certificate2(certBytes, privateKeyBytes, "password");
248+
249+
using (WebServer server = new WebServer(443, HttpProtocol.Https, new Type[] { typeof(SecureController) }))
250+
{
251+
server.HttpsCert = cert;
252+
server.SslProtocols = SslProtocols.Tls12;
253+
server.Credential = new NetworkCredential("admin", "securepassword");
254+
server.ApiKey = "SecureApiKey456";
255+
256+
server.Start();
257+
Thread.Sleep(Timeout.Infinite);
258+
}
259+
```
260+
261+
## Testing Authentication
262+
263+
### Basic Auth with curl
264+
265+
```bash
266+
# With default credentials
267+
curl -u admin:password http://192.168.1.100/secure/data
268+
269+
# With custom credentials
270+
curl -u customuser:custompass http://192.168.1.100/secure/custom
271+
```
272+
273+
### API Key with curl
274+
275+
```bash
276+
# With API key
277+
curl -H "ApiKey: MySecretApiKey123" http://192.168.1.100/api/data
278+
279+
# With custom API key
280+
curl -H "ApiKey: special-key-123" http://192.168.1.100/secure/api
281+
```
282+
283+
## Error Responses
284+
285+
### 401 Unauthorized (Basic Auth)
286+
287+
```http
288+
HTTP/1.1 401 Unauthorized
289+
WWW-Authenticate: Basic realm="nanoFramework"
290+
Content-Length: 0
291+
```
292+
293+
### 401 Unauthorized (API Key)
294+
295+
```http
296+
HTTP/1.1 401 Unauthorized
297+
Content-Length: 0
298+
```
299+
300+
### 500 Internal Server Error (Multiple Methods)
301+
302+
When multiple methods match the same route with conflicting authentication, the server returns 500 with details about the conflicting methods.
303+
304+
## Troubleshooting
305+
306+
1. **Always 401**: Check if method requires authentication and credentials are provided
307+
2. **Wrong credentials**: Verify username/password or API key matches configuration
308+
3. **Case sensitivity**: API key header name is case-sensitive (`ApiKey`)
309+
4. **Multiple methods**: Ensure no conflicting methods for the same route/auth combination
310+
5. **Default vs custom**: Remember that method-level attributes override class-level ones

0 commit comments

Comments
 (0)