diff --git a/global/overlay/etc/puppet/soc/facts.d/.empty b/global/overlay/etc/puppet/soc/facts.d/.empty
new file mode 100644
index 0000000..e69de29
diff --git a/global/overlay/etc/puppet/soc/files/sso/acme-dns-auth.py b/global/overlay/etc/puppet/soc/files/sso/acme-dns-auth.py
new file mode 100755
index 0000000..6873088
--- /dev/null
+++ b/global/overlay/etc/puppet/soc/files/sso/acme-dns-auth.py
@@ -0,0 +1,154 @@
+#!/usr/bin/env python3
+import json
+import os
+import requests
+import sys
+
+### EDIT THESE: Configuration values ###
+
+# URL to acme-dns instance
+ACMEDNS_URL = "https://acme-d.sunet.se"
+# Path for acme-dns credential storage
+STORAGE_PATH = "/etc/letsencrypt/acmedns.json"
+# Whitelist for address ranges to allow the updates from
+# Example: ALLOW_FROM = ["192.168.10.0/24", "::1/128"]
+ALLOW_FROM = []
+# Force re-registration. Overwrites the already existing acme-dns accounts.
+FORCE_REGISTER = False
+
+### DO NOT EDIT BELOW THIS POINT ###
+### HERE BE DRAGONS ###
+
+DOMAIN = os.environ["CERTBOT_DOMAIN"]
+if DOMAIN.startswith("*."):
+ DOMAIN = DOMAIN[2:]
+VALIDATION_DOMAIN = "_acme-challenge."+DOMAIN
+VALIDATION_TOKEN = os.environ["CERTBOT_VALIDATION"]
+
+
+class AcmeDnsClient(object):
+ """
+ Handles the communication with ACME-DNS API
+ """
+
+ def __init__(self, acmedns_url):
+ self.acmedns_url = acmedns_url
+
+ def register_account(self, allowfrom):
+ """Registers a new ACME-DNS account"""
+
+ if allowfrom:
+ # Include whitelisted networks to the registration call
+ reg_data = {"allowfrom": allowfrom}
+ res = requests.post(self.acmedns_url+"/register",
+ data=json.dumps(reg_data))
+ else:
+ res = requests.post(self.acmedns_url+"/register")
+ if res.status_code == 201:
+ # The request was successful
+ return res.json()
+ else:
+ # Encountered an error
+ msg = ("Encountered an error while trying to register a new acme-dns "
+ "account. HTTP status {}, Response body: {}")
+ print(msg.format(res.status_code, res.text))
+ sys.exit(1)
+
+ def update_txt_record(self, account, txt):
+ """Updates the TXT challenge record to ACME-DNS subdomain."""
+ update = {"subdomain": account['subdomain'], "txt": txt}
+ headers = {"X-Api-User": account['username'],
+ "X-Api-Key": account['password'],
+ "Content-Type": "application/json"}
+ res = requests.post(self.acmedns_url+"/update",
+ headers=headers,
+ data=json.dumps(update))
+ if res.status_code == 200:
+ # Successful update
+ return
+ else:
+ msg = ("Encountered an error while trying to update TXT record in "
+ "acme-dns. \n"
+ "------- Request headers:\n{}\n"
+ "------- Request body:\n{}\n"
+ "------- Response HTTP status: {}\n"
+ "------- Response body: {}")
+ s_headers = json.dumps(headers, indent=2, sort_keys=True)
+ s_update = json.dumps(update, indent=2, sort_keys=True)
+ s_body = json.dumps(res.json(), indent=2, sort_keys=True)
+ print(msg.format(s_headers, s_update, res.status_code, s_body))
+ sys.exit(1)
+
+class Storage(object):
+ def __init__(self, storagepath):
+ self.storagepath = storagepath
+ self._data = self.load()
+
+ def load(self):
+ """Reads the storage content from the disk to a dict structure"""
+ data = dict()
+ filedata = ""
+ try:
+ with open(self.storagepath, 'r') as fh:
+ filedata = fh.read()
+ except IOError as e:
+ if os.path.isfile(self.storagepath):
+ # Only error out if file exists, but cannot be read
+ print("ERROR: Storage file exists but cannot be read")
+ sys.exit(1)
+ try:
+ data = json.loads(filedata)
+ except ValueError:
+ if len(filedata) > 0:
+ # Storage file is corrupted
+ print("ERROR: Storage JSON is corrupted")
+ sys.exit(1)
+ return data
+
+ def save(self):
+ """Saves the storage content to disk"""
+ serialized = json.dumps(self._data)
+ try:
+ with os.fdopen(os.open(self.storagepath,
+ os.O_WRONLY | os.O_CREAT, 0o600), 'w') as fh:
+ fh.truncate()
+ fh.write(serialized)
+ except IOError as e:
+ print("ERROR: Could not write storage file.")
+ sys.exit(1)
+
+ def put(self, key, value):
+ """Puts the configuration value to storage and sanitize it"""
+ # If wildcard domain, remove the wildcard part as this will use the
+ # same validation record name as the base domain
+ if key.startswith("*."):
+ key = key[2:]
+ self._data[key] = value
+
+ def fetch(self, key):
+ """Gets configuration value from storage"""
+ try:
+ return self._data[key]
+ except KeyError:
+ return None
+
+if __name__ == "__main__":
+ # Init
+ client = AcmeDnsClient(ACMEDNS_URL)
+ storage = Storage(STORAGE_PATH)
+
+ # Check if an account already exists in storage
+ account = storage.fetch(DOMAIN)
+ if FORCE_REGISTER or not account:
+ # Create and save the new account
+ account = client.register_account(ALLOW_FROM)
+ storage.put(DOMAIN, account)
+ storage.save()
+
+ # Display the notification for the user to update the main zone
+ msg = "Please add the following CNAME record to your main DNS zone:\n{}"
+ cname = "{} CNAME {}.".format(VALIDATION_DOMAIN, account["fulldomain"])
+ print(msg.format(cname))
+
+ # Update the TXT record in acme-dns instance
+ client.update_txt_record(account, VALIDATION_TOKEN)
diff --git a/global/overlay/etc/puppet/soc/files/sso/apache-ssl.conf b/global/overlay/etc/puppet/soc/files/sso/apache-ssl.conf
new file mode 100644
index 0000000..6f61ba9
--- /dev/null
+++ b/global/overlay/etc/puppet/soc/files/sso/apache-ssl.conf
@@ -0,0 +1,19 @@
+# This file contains important security parameters. If you modify this file
+# manually, Certbot will be unable to automatically provide future security
+# updates. Instead, Certbot will print and log an error message with a path to
+# the up-to-date file that you will need to refer to when manually updating
+# this file. Contents are based on https://ssl-config.mozilla.org
+
+SSLEngine on
+
+# Intermediate configuration, tweak to your needs
+SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
+SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
+SSLHonorCipherOrder off
+SSLSessionTickets off
+
+SSLOptions +StrictRequire
+
+# Add vhost name to log entries:
+LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined
+LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common
\ No newline at end of file
diff --git a/global/overlay/etc/puppet/soc/files/sso/attribute-map.xml b/global/overlay/etc/puppet/soc/files/sso/attribute-map.xml
new file mode 100644
index 0000000..6555029
--- /dev/null
+++ b/global/overlay/etc/puppet/soc/files/sso/attribute-map.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/global/overlay/etc/puppet/soc/files/sso/attribute-policy.xml b/global/overlay/etc/puppet/soc/files/sso/attribute-policy.xml
new file mode 100644
index 0000000..00b1455
--- /dev/null
+++ b/global/overlay/etc/puppet/soc/files/sso/attribute-policy.xml
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/global/overlay/etc/puppet/soc/files/sso/md-signer2.crt b/global/overlay/etc/puppet/soc/files/sso/md-signer2.crt
new file mode 100644
index 0000000..f182c7a
--- /dev/null
+++ b/global/overlay/etc/puppet/soc/files/sso/md-signer2.crt
@@ -0,0 +1,33 @@
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
diff --git a/global/overlay/etc/puppet/soc/manifests/.empty b/global/overlay/etc/puppet/soc/manifests/.empty
new file mode 100644
index 0000000..e69de29
diff --git a/global/overlay/etc/puppet/soc/manifests/sso.pp b/global/overlay/etc/puppet/soc/manifests/sso.pp
new file mode 100644
index 0000000..2bb9def
--- /dev/null
+++ b/global/overlay/etc/puppet/soc/manifests/sso.pp
@@ -0,0 +1,176 @@
+## Copy from CNAAS, modifications for Sunet CERT
+#
+# General SSO documentation: https://wiki.sunet.se/x/sZGLBg
+#
+# @param hostname FQDN of the host this is running on.
+#
+# @param email Support email used in error messages etc.
+#
+# @param service_endpoint Location of service to reverse proxy for.
+#
+# @param groups
+# List of user groups from sso_groups in global/overlay/etc/hiera/data/common.yaml. The
+# default is a non-existing placeholder group, added to make the Apache config valid.
+#
+# @param passthrough List of paths to disable SAML protection for, e.g. API paths.
+#
+# @param x_remote_user
+# If true, EPPN is put in the HTTP header X-Remote-User instead of REMOTE_USER.
+#
+# @param single_user
+# If true, EPPN is discarded and X-Remote-User is set to "cnaas-user". This is useful in
+# cases where the service we reverse proxy for can't create new accounts automatically.
+# We use this only for Graylog at the time of writing.
+#
+# @param swamid_testing Set this to true if your SP is registered in swamid-testing.
+#
+# @param front_clients
+# Hiera field, defined at common.yaml, with the the frontend IP prefixes that require access
+# to port 443. Defaults to empty string.
+#
+class cnaas::sso(
+ $hostname,
+ $email,
+ $service_endpoint,
+ $groups = ['PLACEHOLDER'],
+ $passthrough = [],
+ $x_remote_user = false,
+ $swamid_testing = false,
+ $single_user = false,
+ $front_clients = '',
+ $translog = 'INFO',
+ $certbot = true,
+) {
+
+ file { '/opt/sso':
+ ensure => directory,
+ }
+
+ #
+ # Apache files
+ #
+
+ file { '/opt/sso/apache':
+ ensure => directory,
+ }
+
+ file { '/opt/sso/apache/site.conf':
+ ensure => file,
+ content => template('soc/sso/apache-site.conf.erb'),
+ }
+
+ # SSL defaults copied from certbot:
+ # https://github.com/certbot/certbot/blob/master/certbot-apache/certbot_apache/_internal/tls_configs/current-options-ssl-apache.conf
+ file { '/opt/sso/apache/ssl.conf':
+ ensure => file,
+ content => file('soc/sso/apache-ssl.conf'),
+ }
+
+ file { '/opt/sso/apache/groups.txt':
+ ensure => file,
+ content => template('soc/sso/apache-groups.txt.erb')
+ }
+
+ #
+ # Shibboleth files
+ #
+
+ file { '/opt/sso/shibboleth':
+ ensure => directory,
+ }
+
+ file { '/opt/sso/shibboleth/shibboleth2.xml':
+ ensure => file,
+ content => template('soc/sso/shibboleth2.xml.erb'),
+ }
+
+ file { '/opt/sso/shibboleth/shibd.logger':
+ ensure => file,
+ content => template('soc/sso/shibd.logger.erb'),
+ }
+
+ file { '/opt/sso/shibboleth/attribute-map.xml':
+ ensure => file,
+ content => file('soc/sso/attribute-map.xml'),
+ }
+
+ file { '/opt/sso/shibboleth/md-signer2.crt':
+ ensure => file,
+ content => file('soc/sso/md-signer2.crt'),
+ }
+ sunet::snippets::secret_file { '/opt/sso/shibboleth/sp-key.pem':
+ hiera_key => 'sso_sp_key'
+ }
+
+ #
+ # Certbot
+ #
+
+ if $certbot {
+ package { ['certbot', 'python3-requests']:
+ ensure => 'latest',
+ }
+
+ file { '/etc/letsencrypt/acme-dns-auth.py':
+ ensure => file,
+ content => file('cnaas/sso/acme-dns-auth.py'),
+ mode => '0744',
+ }
+
+ file { '/etc/letsencrypt/renewal-hooks/deploy/soc-sso-reload':
+ ensure => file,
+ mode => '0700',
+ content => "#!/bin/sh -eu\ndocker exec sso service apache2 reload",
+ }
+
+ sunet::scriptherder::cronjob { 'le_renew':
+ cmd => '/bin/echo "Keeping this cronjob, but disabled to avoid scriptherder complainign about unknown check"',
+ special => 'daily',
+ }
+ }
+
+ #
+ # Docker
+ #
+
+ exec {"Create Docker network \"sso\" to talk to service":
+ # We OR with true to ignore errors, since the network often already exists.
+ # We specify a subnet so that services which have the option/requirement can
+ # specify this subnet as source of trusted proxies. This is used in Graylog,
+ # for example; see setting "trusted_proxies".
+ command => 'docker network create sso --subnet 172.29.0.0/24 || true'
+ }
+
+ file { '/opt/sso/docker-compose.yml':
+ ensure => file,
+ mode => '0600',
+ content => template('soc/sso/docker-compose.yml.erb'),
+ }
+
+ sunet::docker_compose_service { 'sso':
+ description => '',
+ compose_file => '/opt/sso/docker-compose.yml',
+ }
+
+ #
+ # NFT Rules
+ #
+
+ if 'wg0' in $facts['networking']['interfaces'].keys {
+ if $front_clients != '' {
+ $front_clients_exposed = hiera_array($front_clients,[])
+ sunet::nftables::docker_expose { 'clients_https' :
+ allow_clients => $front_clients_exposed,
+ port => 443,
+ iif => 'wg0',
+ }
+ }
+ }
+
+ sunet::nftables::docker_expose { 'apache_sso_https' :
+ allow_clients => ['0.0.0.0/0'],
+ port => 443,
+ iif => 'ens3',
+ }
+
+}
diff --git a/global/overlay/etc/puppet/soc/templates/sso/apache-groups.txt.erb b/global/overlay/etc/puppet/soc/templates/sso/apache-groups.txt.erb
new file mode 100644
index 0000000..27f779a
--- /dev/null
+++ b/global/overlay/etc/puppet/soc/templates/sso/apache-groups.txt.erb
@@ -0,0 +1,3 @@
+<%- scope.call_function('safe_hiera',['sso_groups']).each do | group, users | -%>
+<%= group %>: <% users.each.with_index do | user, i | %><%= user %><%= ' ' if i < (users.size - 1) %><% end %>
+<%- end -%>
diff --git a/global/overlay/etc/puppet/soc/templates/sso/apache-site.conf.erb b/global/overlay/etc/puppet/soc/templates/sso/apache-site.conf.erb
new file mode 100644
index 0000000..5dfd133
--- /dev/null
+++ b/global/overlay/etc/puppet/soc/templates/sso/apache-site.conf.erb
@@ -0,0 +1,63 @@
+
+
+ # The ServerName directive sets the request scheme, hostname and port that
+ # the server uses to identify itself. This is used when creating
+ # redirection URLs. In the context of virtual hosts, the ServerName
+ # specifies what hostname must appear in the request's Host: header to
+ # match this virtual host. For the default virtual host (this file) this
+ # value is not decisive as it is used as a last resort host regardless.
+ # However, you must set it for any further virtual host explicitly.
+
+ ServerName <%= @hostname %>
+ ServerAdmin <%= @email %>
+
+ # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
+ # error, crit, alert, emerg.
+ # It is also possible to configure the loglevel for particular
+ # modules, e.g.
+ #LogLevel info ssl:warn
+
+ ErrorLog ${APACHE_LOG_DIR}/error.log
+ CustomLog ${APACHE_LOG_DIR}/access.log combined
+
+ # For most configuration files from conf-available/, which are
+ # enabled or disabled at a global level, it is possible to
+ # include a line for only one particular virtual host. For example the
+ # following line enables the CGI configuration for this host only
+ # after it has been globally disabled with "a2disconf".
+ #Include conf-available/serve-cgi-bin.conf
+
+
+ AuthType shibboleth
+ ShibRequestSetting requireSession On
+
+ <%- if @x_remote_user -%>
+ RequestHeader set X-Remote-User %{REMOTE_USER}s
+ <%- elsif @single_user -%>
+ RequestHeader set X-Remote-User soc-user
+ <%- else -%>
+ ShibUseHeaders On
+ <%- end -%>
+
+ AuthGroupFile /etc/apache2/groups.txt
+ Require group <% @groups.each.with_index do |group, i| %><%= group %><%= ' ' if i < (@groups.size - 1) %><% end %>
+
+ <%- @passthrough.each do |path| -%>
+
+ >
+ AuthType None
+ Require all granted
+
+ <%- end -%>
+
+ ProxyPass "/" "<%= @service_endpoint %>/"
+ ProxyPassReverse "/" "<%= @service_endpoint %>/"
+ UseCanonicalName On
+ ProxyPreserveHost On
+
+ ServerAlias <%= @hostname %>
+ SSLCertificateFile /etc/letsencrypt/live/<%= @hostname %>/fullchain.pem
+ SSLCertificateKeyFile /etc/letsencrypt/live/<%= @hostname %>/privkey.pem
+ Include /etc/apache2/ssl.conf
+
+
diff --git a/global/overlay/etc/puppet/soc/templates/sso/docker-compose.yml.erb b/global/overlay/etc/puppet/soc/templates/sso/docker-compose.yml.erb
new file mode 100644
index 0000000..e1813f8
--- /dev/null
+++ b/global/overlay/etc/puppet/soc/templates/sso/docker-compose.yml.erb
@@ -0,0 +1,23 @@
+version: "3"
+services:
+ sso:
+ container_name: sso
+ image: "docker.sunet.se/apache-shib"
+ ports:
+ - "443:443"
+ networks:
+ - sso
+ volumes:
+ - /etc/letsencrypt:/etc/letsencrypt
+ - ./apache/site.conf:/etc/apache2/sites-enabled/site.conf
+ - ./apache/ssl.conf:/etc/apache2/ssl.conf
+ - ./apache/groups.txt:/etc/apache2/groups.txt
+ - ./shibboleth/shibboleth2.xml:/etc/shibboleth/shibboleth2.xml
+ - ./shibboleth/shibd.logger:/etc/shibboleth/shibd.logger
+ - ./shibboleth/attribute-map.xml:/etc/shibboleth/attribute-map.xml
+ - ./shibboleth/md-signer2.crt:/etc/shibboleth/md-signer2.crt
+ - ./shibboleth/sp-cert.pem:/etc/shibboleth/sp-cert.pem
+ - ./shibboleth/sp-key.pem:/etc/shibboleth/sp-key.pem
+networks:
+ sso:
+ external: true
diff --git a/global/overlay/etc/puppet/soc/templates/sso/shibboleth2.xml.erb b/global/overlay/etc/puppet/soc/templates/sso/shibboleth2.xml.erb
new file mode 100644
index 0000000..cae74ac
--- /dev/null
+++ b/global/overlay/etc/puppet/soc/templates/sso/shibboleth2.xml.erb
@@ -0,0 +1,140 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SAML2 Local
+
+
+
+ <%- if @swamid_testing -%>
+
+ <%- else -%>
+
+ <%- end -%>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <%- if @swamid_testing -%>
+
+
+
+ <%- elsif @satosa -%>
+
+ <%- else -%>
+
+
+
+ <%- end -%>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/global/overlay/etc/puppet/soc/templates/sso/shibd.logger.erb b/global/overlay/etc/puppet/soc/templates/sso/shibd.logger.erb
new file mode 100644
index 0000000..815e714
--- /dev/null
+++ b/global/overlay/etc/puppet/soc/templates/sso/shibd.logger.erb
@@ -0,0 +1,72 @@
+# set overall behavior
+log4j.rootCategory=INFO, shibd_log, warn_log
+
+# fairly verbose for DEBUG, so generally leave at INFO
+log4j.category.XMLTooling.XMLObject=INFO
+log4j.category.XMLTooling.KeyInfoResolver=INFO
+log4j.category.Shibboleth.IPRange=INFO
+log4j.category.Shibboleth.PropertySet=INFO
+
+# raise for low-level tracing of SOAP client HTTP/SSL behavior
+log4j.category.XMLTooling.libcurl=INFO
+
+# useful categories to tune independently:
+#
+# tracing of SAML messages and security policies
+#log4j.category.OpenSAML.MessageDecoder=DEBUG
+#log4j.category.OpenSAML.MessageEncoder=DEBUG
+#log4j.category.OpenSAML.SecurityPolicyRule=DEBUG
+#log4j.category.XMLTooling.SOAPClient=DEBUG
+# interprocess message remoting
+#log4j.category.Shibboleth.Listener=DEBUG
+# mapping of requests to applicationId
+#log4j.category.Shibboleth.RequestMapper=DEBUG
+# high level session cache operations
+#log4j.category.Shibboleth.SessionCache=DEBUG
+# persistent storage and caching
+#log4j.category.XMLTooling.StorageService=DEBUG
+
+# logs XML being signed or verified if set to DEBUG
+log4j.category.XMLTooling.Signature.Debugger=INFO, sig_log
+log4j.additivity.XMLTooling.Signature.Debugger=false
+log4j.ownAppenders.XMLTooling.Signature.Debugger=true
+
+# the tran log blocks the "default" appender(s) at runtime
+# Level should be left at INFO for this category
+log4j.category.Shibboleth-TRANSACTION=<%= @translog %>, tran_log
+log4j.additivity.Shibboleth-TRANSACTION=false
+log4j.ownAppenders.Shibboleth-TRANSACTION=true
+
+# uncomment to suppress particular event types
+#log4j.category.Shibboleth-TRANSACTION.AuthnRequest=WARN
+#log4j.category.Shibboleth-TRANSACTION.Login=WARN
+#log4j.category.Shibboleth-TRANSACTION.Logout=WARN
+
+# define the appenders
+
+log4j.appender.shibd_log=org.apache.log4j.RollingFileAppender
+log4j.appender.shibd_log.fileName=/var/log/shibboleth/shibd.log
+log4j.appender.shibd_log.maxFileSize=1000000
+log4j.appender.shibd_log.maxBackupIndex=10
+log4j.appender.shibd_log.layout=org.apache.log4j.PatternLayout
+log4j.appender.shibd_log.layout.ConversionPattern=%d{%Y-%m-%d %H:%M:%S} %p %c %x: %m%n
+
+log4j.appender.warn_log=org.apache.log4j.RollingFileAppender
+log4j.appender.warn_log.fileName=/var/log/shibboleth/shibd_warn.log
+log4j.appender.warn_log.maxFileSize=1000000
+log4j.appender.warn_log.maxBackupIndex=10
+log4j.appender.warn_log.layout=org.apache.log4j.PatternLayout
+log4j.appender.warn_log.layout.ConversionPattern=%d{%Y-%m-%d %H:%M:%S} %p %c %x: %m%n
+log4j.appender.warn_log.threshold=WARN
+
+log4j.appender.tran_log=org.apache.log4j.RollingFileAppender
+log4j.appender.tran_log.fileName=/var/log/shibboleth/transaction.log
+log4j.appender.tran_log.maxFileSize=1000000
+log4j.appender.tran_log.maxBackupIndex=20
+log4j.appender.tran_log.layout=org.apache.log4j.PatternLayout
+log4j.appender.tran_log.layout.ConversionPattern=%d{%Y-%m-%d %H:%M:%S}|%c|%m%n
+
+log4j.appender.sig_log=org.apache.log4j.FileAppender
+log4j.appender.sig_log.fileName=/var/log/shibboleth/signature.log
+log4j.appender.sig_log.layout=org.apache.log4j.PatternLayout
+log4j.appender.sig_log.layout.ConversionPattern=%m