mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-09-13 03:31:31 +03:00
Complete folder anatomy for all 649 cybersecurity skills + update LICENSE to Mahipal
- Add scripts/agent.py and references/api-reference.md to all remaining skills - Update all 648 LICENSE files: copyright now reads 'Mahipal' - Add implementing-security-monitoring-with-datadog (new skill with full anatomy) - All 649 skills now have: SKILL.md, LICENSE, scripts/agent.py, references/api-reference.md
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Anthropic Agent Skills Contributors
|
||||
Copyright (c) 2025 Mahipal
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
# API Reference: SAML Azure AD Federation
|
||||
|
||||
## Federation Metadata URL
|
||||
```
|
||||
https://login.microsoftonline.com/{tenant-id}/federationmetadata/2007-06/federationmetadata.xml
|
||||
```
|
||||
|
||||
## SAML 2.0 Endpoints
|
||||
| Endpoint | URL |
|
||||
|----------|-----|
|
||||
| SSO (POST) | `https://login.microsoftonline.com/{tenant}/saml2` |
|
||||
| SSO (Redirect) | `https://login.microsoftonline.com/{tenant}/saml2` |
|
||||
| Logout | `https://login.microsoftonline.com/{tenant}/saml2` |
|
||||
|
||||
## SP Metadata Required Fields
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `entityID` | SP unique identifier |
|
||||
| `AssertionConsumerService` | ACS URL (POST binding) |
|
||||
| `NameIDFormat` | emailAddress or persistent |
|
||||
| `SingleLogoutService` | SLO URL (optional) |
|
||||
|
||||
## XML Namespaces
|
||||
```python
|
||||
ns = {
|
||||
"md": "urn:oasis:names:tc:SAML:2.0:metadata",
|
||||
"ds": "http://www.w3.org/2000/09/xmldsig#",
|
||||
"saml": "urn:oasis:names:tc:SAML:2.0:assertion",
|
||||
}
|
||||
```
|
||||
|
||||
## SAML Bindings
|
||||
| Binding | URI |
|
||||
|---------|-----|
|
||||
| HTTP-POST | `urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST` |
|
||||
| HTTP-Redirect | `urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect` |
|
||||
| SOAP | `urn:oasis:names:tc:SAML:2.0:bindings:SOAP` |
|
||||
|
||||
## Azure AD Graph API (App Registration)
|
||||
```
|
||||
POST https://graph.microsoft.com/v1.0/servicePrincipals
|
||||
Authorization: Bearer TOKEN
|
||||
{
|
||||
"appId": "app-id",
|
||||
"preferredSingleSignOnMode": "saml",
|
||||
"loginUrl": "https://app.example.com/login"
|
||||
}
|
||||
```
|
||||
|
||||
## Validation Checks
|
||||
| Check | Severity |
|
||||
|-------|----------|
|
||||
| HTTPS on ACS URL | High |
|
||||
| Certificate present | Critical |
|
||||
| HTTP-POST binding available | Medium |
|
||||
| NameID format configured | Medium |
|
||||
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env python3
|
||||
"""SAML Azure AD Federation Agent - Configures and validates SAML SSO with Azure AD."""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import argparse
|
||||
import xml.etree.ElementTree as ET
|
||||
from datetime import datetime
|
||||
|
||||
import requests
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def fetch_federation_metadata(tenant_id):
|
||||
"""Fetch Azure AD SAML federation metadata."""
|
||||
url = f"https://login.microsoftonline.com/{tenant_id}/federationmetadata/2007-06/federationmetadata.xml"
|
||||
resp = requests.get(url, timeout=15)
|
||||
resp.raise_for_status()
|
||||
logger.info("Fetched federation metadata for tenant %s", tenant_id)
|
||||
return resp.text
|
||||
|
||||
|
||||
def parse_metadata(xml_text):
|
||||
"""Parse SAML federation metadata XML."""
|
||||
ns = {"md": "urn:oasis:names:tc:SAML:2.0:metadata", "ds": "http://www.w3.org/2000/09/xmldsig#"}
|
||||
root = ET.fromstring(xml_text)
|
||||
idp_desc = root.find(".//md:IDPSSODescriptor", ns)
|
||||
sso_services = []
|
||||
if idp_desc is not None:
|
||||
for sso in idp_desc.findall("md:SingleSignOnService", ns):
|
||||
sso_services.append({"binding": sso.get("Binding"), "location": sso.get("Location")})
|
||||
certs = []
|
||||
for cert_elem in root.findall(".//ds:X509Certificate", ns):
|
||||
if cert_elem.text:
|
||||
certs.append(cert_elem.text.strip()[:100] + "...")
|
||||
entity_id = root.get("entityID", "")
|
||||
return {"entity_id": entity_id, "sso_services": sso_services, "certificates": certs}
|
||||
|
||||
|
||||
def generate_sp_metadata(entity_id, acs_url, slo_url=None):
|
||||
"""Generate Service Provider SAML metadata."""
|
||||
metadata = {
|
||||
"entityID": entity_id,
|
||||
"assertionConsumerService": {"binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST", "location": acs_url},
|
||||
"nameIDFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
|
||||
}
|
||||
if slo_url:
|
||||
metadata["singleLogoutService"] = {"binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect", "location": slo_url}
|
||||
return metadata
|
||||
|
||||
|
||||
def validate_configuration(idp_metadata, sp_config):
|
||||
"""Validate SAML federation configuration."""
|
||||
findings = []
|
||||
if not idp_metadata.get("sso_services"):
|
||||
findings.append({"issue": "No SSO services in IdP metadata", "severity": "critical"})
|
||||
if not idp_metadata.get("certificates"):
|
||||
findings.append({"issue": "No signing certificates in metadata", "severity": "critical"})
|
||||
if not sp_config.get("assertionConsumerService", {}).get("location", "").startswith("https://"):
|
||||
findings.append({"issue": "ACS URL not using HTTPS", "severity": "high"})
|
||||
http_redirect = any("HTTP-Redirect" in s.get("binding", "") for s in idp_metadata.get("sso_services", []))
|
||||
http_post = any("HTTP-POST" in s.get("binding", "") for s in idp_metadata.get("sso_services", []))
|
||||
if not http_post:
|
||||
findings.append({"issue": "HTTP-POST binding not available", "severity": "medium"})
|
||||
return {"valid": len([f for f in findings if f["severity"] == "critical"]) == 0, "findings": findings}
|
||||
|
||||
|
||||
def generate_report(idp_metadata, sp_config, validation):
|
||||
"""Generate SAML federation report."""
|
||||
report = {
|
||||
"timestamp": datetime.utcnow().isoformat(),
|
||||
"idp_metadata": idp_metadata,
|
||||
"sp_configuration": sp_config,
|
||||
"validation": validation,
|
||||
}
|
||||
status = "VALID" if validation["valid"] else "INVALID"
|
||||
print(f"SAML REPORT: {status}, {len(validation['findings'])} findings")
|
||||
return report
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="SAML Azure AD Federation Agent")
|
||||
parser.add_argument("--tenant-id", required=True, help="Azure AD tenant ID")
|
||||
parser.add_argument("--sp-entity-id", required=True, help="Service Provider entity ID")
|
||||
parser.add_argument("--acs-url", required=True, help="Assertion Consumer Service URL")
|
||||
parser.add_argument("--slo-url", help="Single Logout URL")
|
||||
parser.add_argument("--output", default="saml_report.json")
|
||||
args = parser.parse_args()
|
||||
|
||||
xml_text = fetch_federation_metadata(args.tenant_id)
|
||||
idp_metadata = parse_metadata(xml_text)
|
||||
sp_config = generate_sp_metadata(args.sp_entity_id, args.acs_url, args.slo_url)
|
||||
validation = validate_configuration(idp_metadata, sp_config)
|
||||
|
||||
report = generate_report(idp_metadata, sp_config, validation)
|
||||
with open(args.output, "w") as f:
|
||||
json.dump(report, f, indent=2)
|
||||
logger.info("Report saved to %s", args.output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user