-
Notifications
You must be signed in to change notification settings - Fork 0
Home
- Overview
- Core Components
- Installation & Setup
- API Reference
- Usage Examples
- Configuration Options
- Security Features
- Testing
- Troubleshooting
- Contributing
Secure.SAML is a robust .NET utility library designed to generate signed SAML 2.0 Response messages. It provides a clean, type-safe API for creating SAML assertions with support for multiple cryptographic signing algorithms and flexible configuration options.
- Multiple Signing Algorithms: Supports SHA1, SHA256, and SHA512
- Flexible Signing: Sign either the entire Response or individual Assertion
- Multiple Output Formats: XML Document or Base64 encoded string
- Cross-Platform: Supports .NET Framework 4.6.2+, .NET Standard 2.0+, and .NET 9.0
- Type Safety: Strongly-typed parameters and validation
- Extensible: Factory pattern for custom signing algorithms
- .NET Framework 4.6.2+
- .NET Standard 2.0+
- .NET Standard 2.1+
- .NET 9.0
- Factory Pattern: For creating signing algorithms and signers
- Strategy Pattern: For different signing algorithms
- Builder Pattern: For constructing SAML parameters
- Interface Segregation: Clean separation of concerns
The primary entry point for creating SAML responses.
Key Responsibilities:
- Orchestrates SAML response creation
- Manages signing process
- Handles XML document generation
- Coordinates between parameters and signing infrastructure
Key Methods:
-
Create(Parameters parameters): Returns XMLDocument with signed SAML -
CreateEncoded(Parameters parameters): Returns Base64 encoded string
Configuration container for SAML generation.
Core Properties:
public class Parameters
{
public string Issuer { get; set; } // Issuer name/domain
public string Recipient { get; set; } // Consumer service URL
public string[] AudienceRestrictions { get; set; } // Audience restrictions
public string NamedId { get; set; } // User identity/subject
public NameIdFormat NameIdFormat { get; set; } // Name ID format
public Dictionary<string, string> Attributes { get; set; } // Custom attributes
public SignType SignatureType { get; set; } // Response or Assertion signing
public int NotOnOrAfterInMinutes { get; } // Validity period
public SigningAlgorithm SigningAlgorithm { get; set; } // Cryptographic algorithm
public DateTime Timestamp { get; } // Message timestamp
}Default Values:
-
NotOnOrAfterInMinutes: 10 minutes -
SignatureType: Response signing -
NameIdFormat: Unspecified -
SigningAlgorithm: SHA512 -
Timestamp: Current UTC time -
SamlId&AssertionId: Auto-generated GUIDs
Creates appropriate signer instances based on the requested algorithm.
Supported Algorithms:
-
SHA1:
SigningAlgorithm.SHA1 -
SHA256:
SigningAlgorithm.SHA256 -
SHA512:
SigningAlgorithm.SHA512(Default)
Handles the actual XML signing process using the selected algorithm.
Signing Process:
- Loads X.509 certificate
- Applies canonicalization (Exclusive Canonical XML)
- Creates digital signature
- Embeds signature in XML document
- Adds certificate information
Each algorithm implements ISigningAlgorithm interface:
public interface ISigningAlgorithm
{
string CanonicalizationMethod { get; }
string SignatureMethod { get; }
string DigestMethod { get; }
void AddTransforms(Reference reference);
}Contains generated classes from SAML 2.0 XSD schemas:
saml-schema-assertion-2.0.xsdsaml-schema-protocol-2.0.xsdxmldsig-core-schema.xsdxenc-core-schema.xsd
Install-Package Secure.SAMLusing Secure.SAML;
using Secure.SAML.v2;
// Create SAML instance with certificate factory
var saml = new SAML(() => GetSigningCertificate());// Register in your DI container
services.AddSingleton<ISAML>(provider =>
new SAML(() => GetSigningCertificate()));
// Or with custom certificate factory
services.AddSingleton<ISAML>(provider =>
new SAML(() => CertificateService.GetSigningCertificate()));public interface ISAML
{
/// <summary>
/// Creates a signed SAML Response as XmlDocument
/// </summary>
XmlDocument Create(Parameters parameters);
/// <summary>
/// Creates a signed SAML Response as Base64 encoded string
/// </summary>
string CreateEncoded(Parameters parameters);
}var parameters = new Parameters
{
Issuer = "https://your-domain.com",
Recipient = "https://sp-domain.com/saml/acs",
AudienceRestrictions = new[] { "sp-domain.com" },
NamedId = "user123@domain.com",
NameIdFormat = NameIdFormat.EmailAddress,
Attributes = new Dictionary<string, string>
{
{ "FirstName", "John" },
{ "LastName", "Doe" },
{ "Email", "john.doe@domain.com" }
},
SignatureType = SignType.Response,
NotOnOrAfterInMinutes = 15,
SigningAlgorithm = SigningAlgorithm.SHA256
};public enum SignType
{
Response, // Sign the entire SAML Response
Assertion // Sign only the SAML Assertion
}public enum NameIdFormat
{
None, // No format specified
Unspecified, // urn:oasis:names:tc:SAML:2.0:nameid-format:unspecified
EmailAddress, // urn:oasis:names:tc:SAML:2.0:nameid-format:emailAddress
X509SubjectName, // urn:oasis:names:tc:SAML:2.0:nameid-format:X509SubjectName
WindowsDomainQualifiedName, // urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName
Kerberos, // urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos
Entity, // urn:oasis:names:tc:SAML:2.0:nameid-format:entity
Persistent, // urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
Transient // urn:oasis:names:tc:SAML:2.0:nameid-format:transient
}public enum SigningAlgorithm
{
SHA1, // SHA-1 with RSA (legacy support)
SHA256, // SHA-256 with RSA (recommended)
SHA512 // SHA-512 with RSA (maximum security)
}var saml = new SAML(() => GetSigningCertificate());
var parameters = new Parameters
{
Issuer = "https://idp.company.com",
Recipient = "https://app.company.com/saml/acs",
AudienceRestrictions = new[] { "app.company.com" },
NamedId = "john.doe@company.com",
NameIdFormat = NameIdFormat.EmailAddress,
Attributes = new Dictionary<string, string>
{
{ "Department", "Engineering" },
{ "Role", "Developer" }
}
};
// Generate XML document
var xmlDocument = saml.Create(parameters);
// Generate Base64 encoded string
var base64String = saml.CreateEncoded(parameters);var parameters = new Parameters
{
Issuer = "https://idp.company.com",
Recipient = "https://app.company.com/saml/acs",
AudienceRestrictions = new[] { "app.company.com", "legacy-app.company.com" },
NamedId = "john.doe@company.com",
NameIdFormat = NameIdFormat.Persistent,
Attributes = new Dictionary<string, string>
{
{ "EmployeeId", "EMP001" },
{ "Groups", "Developers,Admins" },
{ "LastLogin", DateTime.UtcNow.ToString("O") }
},
SignatureType = SignType.Assertion, // Sign only the assertion
NotOnOrAfterInMinutes = 30, // 30 minute validity
SigningAlgorithm = SigningAlgorithm.SHA256,
SamlId = Guid.Parse("95AD6A84-95C1-4B39-AE5E-FE1E700C406C"),
AssertionId = Guid.Parse("B3CA912A-4A6B-4F31-9FD8-FC5E55837656"),
Timestamp = DateTime.Parse("2024-01-15T10:00:00Z")
};public class CertificateService
{
public static X509Certificate2 GetSigningCertificate()
{
// Load from certificate store
using var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
var cert = store.Certificates.Find(
X509FindType.FindBySubjectName,
"SAML-Signing-Certificate",
false)[0];
return cert;
}
}
var saml = new SAML(CertificateService.GetSigningCertificate);public class SamlService
{
private readonly ISAML _saml;
public SamlService(ISAML saml)
{
_saml = saml;
}
public string CreateSamlResponse(string userId, Dictionary<string, string> attributes)
{
var parameters = new Parameters
{
Issuer = Configuration["Saml:Issuer"],
Recipient = Configuration["Saml:Recipient"],
AudienceRestrictions = Configuration.GetSection("Saml:AudienceRestrictions").Get<string[]>(),
NamedId = userId,
Attributes = attributes,
SigningAlgorithm = SigningAlgorithm.SHA256
};
return _saml.CreateEncoded(parameters);
}
}
// Registration
services.AddScoped<SamlService>();
services.AddSingleton<ISAML>(provider =>
new SAML(() => CertificateService.GetSigningCertificate()));- Issuer: Identity Provider identifier
- Recipient: Service Provider assertion consumer service URL
- Audience Restrictions: List of allowed audience URLs
- Name ID: User identifier (email, username, etc.)
- Name ID Format: SAML name identifier format
- Custom Attributes: Key-value pairs for user data
- Signature Type: Response or Assertion signing
- Validity Period: NotOnOrAfter time in minutes
- Signing Algorithm: Cryptographic algorithm selection
- Timestamps: Custom issue and validity times
- IDs: Custom SAML and Assertion identifiers
- Certificate Management: X.509 certificate loading and validation
- Algorithm Selection: Choose appropriate cryptographic strength
- Signature Placement: Control what gets signed
- Validity Windows: Configure time-based restrictions
- RSA Digital Signatures: Industry-standard asymmetric cryptography
- Multiple Hash Algorithms: SHA1, SHA256, SHA512 support
- XML Digital Signature: Compliant with XML-DSig standard
- Certificate Validation: X.509 certificate integration
- Audience Restrictions: Prevent assertion forwarding attacks
- Time-based Validity: Configurable expiration windows
- Signature Verification: Built-in signature validation methods
- Canonicalization: Exclusive Canonical XML for consistent signing
- Use SHA256 or SHA512 for new implementations
- Implement proper certificate lifecycle management
- Validate all input parameters
- Use appropriate validity windows
- Monitor and log SAML operations
The library includes comprehensive test coverage using NUnit and approval testing.
# Navigate to test directory
cd tests/Secure.SAML.Tests
# Run tests
dotnet test- Unit Tests: Individual component testing
- Integration Tests: End-to-end SAML generation
- Approval Tests: XML output validation
- Algorithm Tests: All signing algorithm combinations
- SHA1, SHA256, SHA512 signing algorithms
- Response vs. Assertion signing
- XML document and Base64 output formats
- Parameter validation
- Error handling scenarios
// Ensure certificate has private key access
var cert = new X509Certificate2("path/to/cert.pfx", "password");
if (!cert.HasPrivateKey)
{
throw new InvalidOperationException("Certificate must have private key");
}// All required parameters must be provided
var parameters = new Parameters
{
Issuer = "https://your-domain.com", // Required
Recipient = "https://sp-domain.com/acs", // Required
NamedId = "user@domain.com" // Required
};
// Validate before use
parameters.Validate();// Check for valid XML output
try
{
var xmlDoc = saml.Create(parameters);
var xmlString = xmlDoc.OuterXml;
// Validate XML can be parsed
var validationDoc = new XmlDocument();
validationDoc.LoadXml(xmlString);
}
catch (XmlException ex)
{
// Handle XML parsing errors
Console.WriteLine($"XML Error: {ex.Message}");
}- Enable XML Validation: Validate generated XML against SAML schemas
- Check Certificate: Ensure certificate is valid and accessible
- Verify Parameters: Validate all required parameters are set
- Monitor Output: Use approval tests to catch regressions
- Log Operations: Add logging for troubleshooting
- Clone the repository
- Install .NET 9.0 SDK
- Restore NuGet packages
- Run tests to verify setup
- Follow existing naming conventions
- Add XML documentation for public APIs
- Include unit tests for new features
- Use approval tests for XML output validation
- Write tests for all new functionality
- Ensure existing tests pass
- Use approval testing for XML output
- Test all signing algorithm combinations
- Create feature branch
- Implement changes with tests
- Ensure all tests pass
- Submit pull request with description
- Address review feedback
Secure.SAML is maintained by CodeShayk and is licensed under the MIT License. For support, please create an issue on the GitHub repository.