Cas: Difference between revisions

From Newroco Tech Docs
Jump to navigationJump to search
 
(90 intermediate revisions by 2 users not shown)
Line 1: Line 1:
==Install Tomcat 8==
=Cas 6.x.x=
==Install Tomcat 9==
<pre>
<pre>
apt-get install openjdk-8-jdk
apt-get install openjdk-11-jdk tomcat9
apt-get install tomcat8
</pre>
</pre>


===Copy certificates from proxy with rsync===
===Generate or Copy certificates from proxy with rsync===
Add the public key of the user that is going to copy the certificates to the /root directory. More details here http://docswiki.newro.co/index.php/SSHKeyAuth#Install_key_authentication_for_an_account. Create script /opt/bin/letsencrypt_sync:
'''1)''' Generate self signed certificates
<pre>mkdir /opt/tomcat-certs && cd /opt/tomcat-certs
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /opt/tomcat-certs/cert.key -out /opt/tomcat-certs/cert.crt
openssl pkcs12 -export -in /opt/tomcat-certs/cert.crt -inkey /opt/tomcat-certs/cert.key -out /opt/tomcat-certs/fullchain_and_key.p12 -name tomcat -password pass:<password>
chown tomcat:tomcat fullchain_and_key.p12</pre>


<pre>
'''2)'''Add the public key of the user that is going to copy the certificates to the /root directory. More details here http://docswiki.newro.co/index.php/SSHKeyAuth#Install_key_authentication_for_an_account. Create script /opt/bin/letsencrypt-sync.sh:
/usr/bin/rsync -rl --safe-links --rsync-path="/usr/bin/sudo /usr/bin/rsync" <user>@<proxy-ip>:/etc/letsencrypt/ /etc/letsencrypt/ 2>&1 >> /var/log/letsencrypt_sync.log
 
<pre>/usr/bin/rsync -rl --safe-links --rsync-path="/usr/bin/sudo /usr/bin/rsync" <user>@<proxy-ip>:/etc/letsencrypt/ /etc/letsencrypt-proxy/ 2>&1 >> /var/log/letsencrypt_sync.log
 
openssl pkcs12 -export -in /etc/letsencrypt-proxy/live/<domain>/fullchain.pem -inkey /etc/letsencrypt-proxy/live/<domain>/privkey.pem -out /opt/bin/fullchain_and_key.p12 -name tomcat -password pass:<password>
 
systemctl restart tomcat9</pre>
 
Make it executable
<pre>chmod +x /opt/bin/letsencrypt-sync.sh</pre>
 
Install rsync if not already
<pre>apt-get install rsync</pre>
 
Run the script for initial copy
<pre>/opt/bin/letsencrypt-sync.sh</pre>


openssl pkcs12 -export -in /etc/letsencrypt/live/<domain>/fullchain.pem -inkey /etc/letsencrypt/live/domain/privkey.pem -out /opt/bin/fullchain_and_key.p12 -name tomcat -password pass:<password>
Make the converted certificate readable for everyone
<pre>chmod +r /opt/bin/fullchain_and_key.p12</pre>


service tomcat8 restart
Create a crontab for automatic copy
</pre>
<pre>vi /etc/cron.d/letsencrypt-sync</pre>
Run the script with sudo and then create a crontab for root.
<pre>
crontab -u root -e
</pre>


And add this to the file:
And add this to the file:
<pre>
<pre>0 1 * * * root /opt/bin/letsencrypt-sync.sh</pre>
0 0 * * * /opt/bin/letsencrypt_sync
</pre>


===Enable SSL===
===Configure Tomcat===
Edit /etc/tomcat8/server.xml, uncomment and change appropriately the next section(change password with what you used in script above):
Enable encryption by editing /etc/tomcat9/server.xml, uncomment and change appropriately the next section(change password with what you used in script above):
<pre>
<pre>
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
    <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
               maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
               maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS"
               clientAuth="false" sslProtocol="TLS"
               keystoreFile="/opt/bin/fullchain_and_key.p12" keystoreType="PKCS12"
               keystoreFile="/opt/tomcat-certs/fullchain_and_key.p12" keystoreType="PKCS12"
               keystorePass="<password>"
               keystorePass="<password>"
               />
               />
</pre>
</pre>


Restart tomcat (service tomcat8 restart) and you should be able to access it at https://server-ip:8443
In the same file, add/modify these lines at the end of the file to let tomcat see the original IP when running behind a reverse proxy
<pre>        <Valve className="org.apache.catalina.valves.RemoteIpValve" />
 
        <!-- Access log processes all example.
            Documentation at: /docs/config/valve.html
            Note: The pattern used is equivalent to using pattern="common" -->
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
                prefix="localhost_access_log" suffix=".txt"
                requestAttributesEnabled="true"
              pattern="%h %l %u %t &quot;%r&quot; %s %b" /></pre>
 
Restart tomcat and you should be able to access it at https://my.domain.com:8443
<pre>systemctl restart tomcat9</pre>
 
 
Add the following argumet to the  HTTPS proxy vhost:
<pre>SSLProxyEngine On</pre>


==Install CAS==
==Install CAS==
First we need to install maven.
Download the CAS Overlay Template needed for installation.
<pre>
<pre>mkdir /opt/cas
apt-get install maven
cd /opt/cas
</pre>
wget https://github.com/apereo/cas-overlay-template/archive/6.6.zip
unzip 6.6.zip
cd cas-overlay-template-6.6</pre>
 
First, you need to open the file '''build.gradle''' and add the necessary dependencies. Here are the base dependencies that you'll most probably need:
<pre>dependencies {
    implementation "org.apereo.cas:cas-server-webapp"
    implementation "org.apereo.cas:cas-server-support-ldap"
    implementation "org.apereo.cas:cas-server-support-jdbc"
    implementation "org.apereo.cas:cas-server-support-jdbc-drivers"
    implementation "org.apereo.cas:cas-server-support-json-service-registry"
    implementation "org.apereo.cas:cas-server-support-saml"
    implementation "org.apereo.cas:cas-server-support-oauth-webflow"
    implementation "org.apereo.cas:cas-server-support-oidc"
    implementation "org.apereo.cas:cas-server-support-simple-mfa"
    implementation "org.apereo.cas:cas-server-support-sms-nexmo"
}</pre>
 
For more dependencies like SAML, OAuth2, OpenID Connect, 2 Factor Authentication, etc. check CAS official documentation: https://apereo.github.io/cas/6.6.x/index.html
 
By default when building CAS, it doesn't make all the resources available, that you need to configure and customize your CAS instance. So you first need to make those resources available for the war file that you'll build.
<pre>./gradlew unzip  ### explodeWar was the valid option before CAS 6.5.x instead of unzip
rm -r src/main/resources/*
cp -r build/cas-resources/* src/main/resources/</pre>
 
'''Note''': if you are also building a failover server as well, or you think you'll need to rebuild the app in the future (e.g. to add another dependency) it will be easier to first configure CAS with the resources you just copied and then build it and copy the cas.war into the tomcat folder on all servers needed.
 
Now we can build the application war file.
<pre>./gradlew clean build [-Pvalidate=false]</pre>


Create a directory to download cas and in that directory create a file pom.xml. The content of pom.xml for the latest CAS version can be taken from https://github.com/apereo/cas-overlay-template/blob/master/pom.xml
Move the resulted war file into the tomcat folder
<pre>
<pre>cp build/libs/cas.war /var/lib/tomcat9/webapps/</pre>
mkdir ~/cas
vi ~/cas/pom.xml
</pre>


If you want CAS to use LDAP then add this to pom.xml inside <dependencies> tag:
'''Note''': CAS 6.1 requires tomcat 9.0.27 (or newer), so if you have an older version of tomcat 9 it can still work but this will need to be set in /var/lib/tomcat9/webapps/cas/WEB-INF/classes/application.properties
<pre>
<pre>spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration</pre>
<dependency>
  <groupId>org.apereo.cas</groupId>
  <artifactId>cas-server-support-ldap</artifactId>
  <version>${cas.version}</version>
</dependency>
</pre>


Now go to ~/cas directory, download CAS and copy cas.war to tomcats webapp folder.
To be able to manage what services/apps are allowed to authenticate through CAS, you need to add this line to the configuration
<pre>
<pre>cas.serviceRegistry.initFromJson=true
cd ~/cas
cas.serviceRegistry.json.location=file:/var/lib/tomcat9/webapps/cas/WEB-INF/classes/services
mvn clean package
cas.logout.followServiceRedirects=true</pre>
cp target/cas.war /var/lib/tomcat8/webapps/
service tomcat8 restart
</pre>


The CAS login page can be found at https://server-ip:8443/cas/login
To set the ticket timeout use
<pre>cas.ticket.tgt.timeout.maxTimeToLiveInSeconds=43200</pre>


===Configure CAS===
If you plan to implement '''OAuth2''' on CAS you should specifically configure the service URL
<pre>cas.server.name=https://cas.domain.com
cas.server.prefix=${cas.server.name}/cas
cas.authn.oauth.user-profile-view-type=FLAT</pre>


If the samba/LDAP server is using a self-signed certificate copy it (from /var/lib/samba/private/tls/samba-cert.pem) to the CAS server in /opt/bin/samba-cert.pem. Create a samba user for CAS to use.
If you plan to implement '''OIDC''' on CAS you should set the issuer URL and keystore location
Back on the CAS server, add a line in /etc/hosts:
<pre>cas.authn.oidc.issuer=https://cas.domain.com/cas/oidc
<pre>
cas.authn.oidc.jwks.jwks-file=file:/var/lib/tomcat9/webapps/cas/WEB-INF/classes/keystore.jwks</pre>
samba-server-ip hostname.domain.local
</pre>


Edit /var/lib/tomcat8/webapps/cas/WEB-INF/classes/application.properties file. Comment if you find a line like this:
Comment these lines from the configuration to disable the default account.
<pre>
<pre>#cas.authn.accept.enabled=true
cas.authn.accept.users=casuser::Mellon
#cas.authn.accept.users=casuser::Mellon
</pre>
#cas.authn.accept.name=Static Credentials</pre>


And add this at the end of the file, changing it for your case:
To set an '''LDAP''' server as the user source use this configuration
<pre>
<pre>cas.authn.ldap[0].providerClass=org.ldaptive.provider.unboundid.UnboundIDProvider
cas.authn.ldap[0].type=AUTHENTICATED
cas.authn.ldap[0].type=AUTHENTICATED
cas.authn.ldap[0].ldapUrl=ldaps://hostname.domain.local
cas.authn.ldap[0].ldapUrl=ldaps://ldap.domain.com
cas.authn.ldap[0].useSsl=true
cas.authn.ldap[0].useSsl=true
cas.authn.ldap[0].useStartTls=false
cas.authn.ldap[0].connectTimeout=5000
cas.authn.ldap[0].connectTimeout=5000
cas.authn.ldap[0].baseDn=cn=Users,dc=DOMAIN,dc=LOCAL
cas.authn.ldap[0].minPoolSize=0
cas.authn.ldap[0].userFilter=sAMAccountName={user}
cas.authn.ldap[0].baseDn=cn=Users,dc=<domain>,dc=local
cas.authn.ldap[0].subtreeSearch=true
cas.authn.ldap[0].searchFilter=sAMAccountName={user}
cas.authn.ldap[0].usePasswordPolicy=true
cas.authn.ldap[0].bindDn=cn=<bind-user>,cn=Users,dc=<domain>,dc=local
cas.authn.ldap[0].bindDn=cn=cas-user,cn=Users,dc=DOMAIN,dc=LOCAL
cas.authn.ldap[0].bindCredential=<password>
cas.authn.ldap[0].bindCredential=cas-user-passwords
cas.authn.ldap[0].trustCertificates=file:/opt/samba-cert/samba-cert.pem
cas.authn.ldap[0].trustCertificates=file:/opt/bin/samba-cert.pem
cas.authn.ldap[0].principalAttributeList=sAMAccountName,mail,displayName</pre>
</pre>
 
Restart tomcat
<pre>systemctl restart tomcat9</pre>
 
==Change login page design==
 
===Add a new logo===
To add logo to the login page first copy the .png file /cas/WEB-INF/classes/static/images directory and change the file ownership to tomcat user:
<pre>sudo chown tomcat:tomcat logo.png</pre>
 
Add following line to /var/lib/tomcat9/webapps/cas/WEB-INF/classes/templates/fragments/header.html before or after the "svg" tag contained in a <a> tag:
<pre><a href="https://newro.co/"><img src="/cas/images/newroco_logo.png" style="width: 375px;height: 55px;"/></a></pre>
 
To remove the drop down menu, remove all the <pre>"<div class="collapse navbar-collapse" id="navbarSupportedContent">"</pre> class.
 
===Change the head bar background color===
 
Add following file to /cas/WEB-INF/classes/static/css/cas.css line 11755:
<pre>header > .navbar {
background-color: #a1b1b9;
color: #fff;</pre>
 
===Change the "Reset password?" button ===
 
Edit the text message /cas/WEB-INF/classes/messages.properties line 27 and the redirect link from /cas/WEB-INF/classes/templates/fragments/pmlinks.html line 32.
 
==OAuth2==
To be able to use the OAuth2 you first need to add this to the dependencies before building CAS
<pre>compile "org.apereo.cas:cas-server-support-oauth-webflow:${project.'cas.version'}"</pre>
 
Now create a json file in /var/lib/tomcat9/webapps/cas/WEB-INF/classes/services/ to allow an app to authenticate with CAS using the OAuth2 protocol
<pre>{
  "@class" : "org.apereo.cas.support.oauth.services.OAuthRegisteredService",
  "clientId": "OAuth2AppToBeAllowed",
  "clientSecret": "<secret>",  ### can be generated with "openssl rand -base64 32"
  "serviceId" : "^https://app.domain.com/path/to/OAuth2/endpoint",
  "name" : "OAuth for my App",
  "id" : 10000002,  ### make sure this id is unique
  "attributeReleasePolicy" : {
    "@class" : "org.apereo.cas.services.ReturnAllowedAttributeReleasePolicy",
    "allowedAttributes" : [ "java.util.ArrayList", [ "sAMAccountName", "mail", "displayName" ] ]
  },
  "bypassApprovalPrompt" : true, ### this is needed so the user won't be asked at every login if he wants to allow the App to use the info provided by CAS
  "evaluationOrder" : 102
}</pre>
 
===Troubleshooting===
In case you need to see how the response from CAS looks like, here is how you can find out. First install jq
<pre>apt-get install jq</pre>
 
Request a token from CAS
<pre>curl https://cas.domain.com/cas/oauth2.0/token?grant_type=password'&'client_id=client'&'client_secret=secret'&'username=my.user'&'password=my-password | jq</pre>
 
Then request the info about the user with the received token
<pre>curl -k --user client:secret https://cas.domain.com/cas/oauth2.0/profile?access_token=AT-1-wiNsTgaHzXLUIyaaoFoip-znohWPihea | jq</pre>
 
Enable debug mode
<pre>logging.level.org.apereo.cas=DEBUG</pre>
 
==2 Factor Authentication (2FA)==
Note: CAS calls 2 Factor Authentication (2FA) as Multifactor Authentication (MFA). Mainly because it is possible to set multiple 2FA options in a certain order (e.g. user/pass -> 2fa sms -> 2fa email -> successful login)
===Email===
To be able to use email 2FA you first need to add this to the dependencies before building CAS
<pre>compile "org.apereo.cas:cas-server-support-simple-mfa:${project.'cas.version'}"</pre>
 
Next you need to install postfix
<pre>apt-get install postfix</pre>
 
Add these lines to the CAS config in /var/lib/tomcat9/webapps/cas/WEB-INF/classes/application.properties
<pre>cas.authn.mfa.globalProviderId=mfa-simple
cas.authn.mfa.simple.name=Email MFA
cas.authn.mfa.simple.order=1
cas.authn.mfa.simple.timeToKillInSeconds=180
cas.authn.mfa.simple.tokenLength=6
 
cas.authn.mfa.simple.mail.from=no-reply@my.domain.com
cas.authn.mfa.simple.mail.text=This is your 2FA code for CAS authentication: %s
cas.authn.mfa.simple.mail.subject=CAS 2FA Code
cas.authn.mfa.simple.mail.validateAddresses=false
cas.authn.mfa.simple.mail.html=false
 
cas.authn.mfa.simple.mail.attributeName=mail
 
spring.mail.host=localhost
spring.mail.port=25
spring.mail.testConnection=true
spring.mail.properties.mail.smtp.auth=false
spring.mail.properties.mail.smtp.starttls.enable=false</pre>
 
===SMS (Nexmo)===
To be able to use SMS 2FA you first need to add this to the dependencies before building CAS
<pre>compile "org.apereo.cas:cas-server-support-simple-mfa:${project.'cas.version'}"
compile "org.apereo.cas:cas-server-support-sms-nexmo:${project.'cas.version'}"</pre>
 
Create an account on Nexmo (https://dashboard.nexmo.com/sign-up). After that create a new application, that should give you an api key and a secret.
 
Add these lines to the CAS config in /var/lib/tomcat9/webapps/cas/WEB-INF/classes/application.properties
<pre>cas.authn.ldap[0].principalAttributeList=mail,telephoneNumber  #you probably have this already in your config just need to add the phone attribute
 
cas.authn.mfa.globalProviderId=mfa-simple
cas.authn.mfa.simple.name=SMS 2FA
cas.authn.mfa.simple.order=1
cas.authn.mfa.simple.timeToKillInSeconds=180
cas.authn.mfa.simple.tokenLength=6
 
cas.authn.mfa.simple.sms.from=CAS
cas.authn.mfa.simple.sms.text=This is your CAS 2FA code: %s
cas.authn.mfa.simple.sms.attributeName=telephoneNumber
 
cas.smsProvider.nexmo.apiToken=<api-key>
cas.smsProvider.nexmo.apiSecret=<api-secret></pre>
 
===Signal===
To be able to send Signal messages we'll use this project: https://github.com/bbernhard/signal-cli-rest-api/
 
First install docker. '''NOTE''': this docker repo is for Ubuntu 20.04
<pre>curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
apt-get install docker-ce</pre>
 
Build and run the docker container for the Signal API
<pre>docker run -d --name signal-api --restart=always -p 127.0.0.1:5000:8080 -v /opt/signal-container-config/signal-cli:/home/.local/share/signal-cli -e 'MODE=json-rpc' bbernhard/signal-cli-rest-api</pre>
 
====Register(1) a phone number for the API or link(2) it as a new device with a pre-registered number====
'''1.'''Go to https://signalcaptchas.org/registration/generate.html, open the developer console on the network tab, solve the captcha and then check the failed redirect to '''signalcaptcha://<captcha-string>'''. Copy the '''<captcha-string>''' after '''signalcaptcha://''' as you'll need it at the next step.
 
Register the phone number you want to use for the Signal API
<pre>curl -X POST 'http://localhost:5000/v1/register/+40712345678' -H 'accept: application/json' -H 'Content-Type: application/json' -d '{"use_voice": false, "captcha": "<captcha-string>"}'</pre>
 
Now you should receive a SMS with the verification code on the phone number you just registered and have to send it to the Signal API
<pre>curl -X POST 'http://localhost:5000/v1/register/+40712345678/verify/<sms-code>' -H 'accept: application/json' -H 'Content-Type: application/json'</pre>
 
'''2.'''Install these packages that help view a qrcode at CLI
<pre>apt-get install zbar-tools qrencode</pre>
 
Get the QR code from the Signal API
<pre>wget http://localhost:5000/v1/qrcodelink?device_name=<server-name> -O /tmp/signal-qrcode.png && zbarimg -q --raw /tmp/signal-qrcode.png | tr -d '\n' | qrencode -l H -t utf8 && rm /tmp/signal-qrcode.png</pre>
 
On the device with Signal already set, open the app, click account avatar, click Linked devices, add new device and scan the QR code you get with the above command.
 
Now you should be able to send Signal messages (with either of the above methods) from your server
<pre>curl -X POST  -d '{"message": "test message from server", "number": "+40712345678", "recipients": [ "+40712345678" ]}' http://localhost:5000/v2/send</pre>
 
If you can't send a message to more then 2 different phone numbers, then you need to enter the docker container and run some commands
<pre># su signal-api
# signal-cli -u <phone-number-to-send-from> send -m "test message from cas-test2" <destination-phone-number-that-failed>
Failed to send (some) messages:
+40712345678: CAPTCHA proof required for sending to "+40712345678", available options "PUSH_CHALLENGE, RECAPTCHA" with challenge token "8dbe5d53-xxxx-xxxx-xxxx-eeeb1e8336e0", or wait "86400" seconds.
To get the captcha token, go to https://signalcaptchas.org/challenge/generate.html
Check the developer tools (F12) console for a failed redirect to signalcaptcha://
Everything after signalcaptcha:// is the captcha token.
Use the following command to submit the captcha token:
signal-cli submitRateLimitChallenge --challenge CHALLENGE_TOKEN --captcha CAPTCHA_TOKEN
# signal-cli submitRateLimitChallenge --challenge 8dbe5d53-xxxx-xxxx-xxxx-eeeb1e8336e0 --captcha signal-recaptcha-v2.6LfBXs...</pre>
 
 
For CAS you'll need this module added when building
<pre>implementation "org.apereo.cas:cas-server-support-simple-mfa"</pre>
 
Create a file for the following groovy script:
<pre>#vi /opt/cas-groovy-scripts/sendSignalMessage.groovy
 
import java.util.*
 
def run(Object[] args) {
    def from = args[0]
    def to = args[1]
    def message = args[2]
    def logger = args[3]
 
    ["curl", "-X", "POST", "-d", "{\"message\": \"${message}\", \"number\": \"+40712345678\", \"recipients\": [ \"${to}\" ]}", "http://localhost:5000/v2/send"].execute()
    return true
}</pre>
 
Make it accessible to tomcat
<pre>chown -R tomcat:tomcat /opt/cas-groovy-scripts</pre>
 
Add these CAS config lines in `/var/lib/tomcat9/webapps/cas/WEB-INF/classes/application.properties`
<pre>##
# Signal 2FA
#
cas.authn.mfa.triggers.global.global-provider-id=mfa-simple
 
cas.authn.mfa.simple.name=Signal 2FA
cas.authn.mfa.simple.order=0
cas.authn.mfa.simple.time-to-kill-in-seconds=180
cas.authn.mfa.simple.token-length=6
 
cas.authn.mfa.simple.sms.from=CAS
cas.authn.mfa.simple.sms.text=This is your CAS 2FA code: %s. The CASMFA- prefix can be excluded.
cas.authn.mfa.simple.sms.attribute-name=telephoneNumber
 
cas.sms-provider.groovy.location=file:/opt/cas-groovy-scripts/sendSignalMessage.groovy</pre>
 
And of course, make sure to retrieve attribute '''telephoneNumber''' from LDAP or what user source you use.
 
====Trusted numbers====
List trusted numbers
<pre>curl -X GET http://localhost:5000/v1/identities/<sending-number></pre>
 
Trust a number ('''untested''')
<pre>curl -X PUT -d '{"trust_all_known_keys": false, "verified_safety_number": "string"}' http://localhost:5000/v1/identities/<sending-number>/trust/<receiving-number></pre>
 
==Internal DNS records==
If the CAS server and other web services that use CAS for authentication are behind the same proxy they will probably need internal DNS records pointing to the internal IP of the proxy to avoid loops in the firewall routing.
 
=Failover=
If you want to have a failover CAS build a second server exactly as above and configure a floating IP with Keepalived as below.
 
===Keepalived===
To setup keepalived, install it on both servers:
<pre>sudo apt-get install keepalived</pre>
 
Copy the nagios check "check_http" to /usr/local/bin, from the /usr/lib/nagios/plugins of a server that has nagios-plugins installed (please don't install nagios-plugins on the CAS servers, that package would install many dependencies).
 
Finally create the following /etc/keepalived/keepalived.conf on the master:
 
<pre>global_defs {
        notification_email {
                <email>
        }
 
        notification_email_from <email>
        smtp_server 127.0.0.1
}
 
vrrp_script chk_apache {
        script "check_http -S -H 127.0.0.1 -u /cas/ -p 8443"
        interval 3                      # check every 3 seconds
        weight 2                        # add 2 points of prio if OK
}


Change this line at the beginning of /var/lib/tomcat8/webapps/cas/WEB-INF/classes/log4j2.xml
vrrp_instance floating_ip {
<pre><Property name="baseDir">/etc/cas/logs</Property></pre>
        interface ens3
To
        state MASTER
<pre><Property name="baseDir">/var/lib/tomcat8/webapps/cas/WEB-INF/classes/logs</Property></pre>
        virtual_router_id 31
        priority 101
        authentication {
            auth_type PASS
            auth_pass justatestpass
        }
        virtual_ipaddress {
                <floating-IP>
        }


Restart tomcat
        track_script {
<pre>
            chk_apache
service tomcat8 restart
        }
</pre>
}</pre>


===Service registry===
Create exactly the same file on the failover CAS, just change priority from 101 to 100.
By default CAS allows all services that come from HTTPS or IMAPS. If you want to change that you can modify /var/lib/tomcat8/webapps/cas/WEB-INF/classes/services/HTTPSandIMAPS-10000001.json or create a another file in the same folder with similar format.


If CAS says that the service is not authorized even if it is add this line to /var/lib/tomcat8/webapps/cas/WEB-INF/classes/application.properties
Restart keepalived
<pre>cas.serviceRegistry.initFromJson=true</pre>
<pre>service keepalived restart</pre>

Latest revision as of 06:02, 8 August 2023

Cas 6.x.x

Install Tomcat 9

apt-get install openjdk-11-jdk tomcat9

Generate or Copy certificates from proxy with rsync

1) Generate self signed certificates

mkdir /opt/tomcat-certs && cd /opt/tomcat-certs
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /opt/tomcat-certs/cert.key -out /opt/tomcat-certs/cert.crt
openssl pkcs12 -export -in /opt/tomcat-certs/cert.crt -inkey /opt/tomcat-certs/cert.key -out /opt/tomcat-certs/fullchain_and_key.p12 -name tomcat -password pass:<password>
chown tomcat:tomcat fullchain_and_key.p12

2)Add the public key of the user that is going to copy the certificates to the /root directory. More details here http://docswiki.newro.co/index.php/SSHKeyAuth#Install_key_authentication_for_an_account. Create script /opt/bin/letsencrypt-sync.sh:

/usr/bin/rsync -rl --safe-links --rsync-path="/usr/bin/sudo /usr/bin/rsync" <user>@<proxy-ip>:/etc/letsencrypt/ /etc/letsencrypt-proxy/ 2>&1 >> /var/log/letsencrypt_sync.log

openssl pkcs12 -export -in /etc/letsencrypt-proxy/live/<domain>/fullchain.pem -inkey /etc/letsencrypt-proxy/live/<domain>/privkey.pem -out /opt/bin/fullchain_and_key.p12 -name tomcat -password pass:<password>

systemctl restart tomcat9

Make it executable

chmod +x /opt/bin/letsencrypt-sync.sh

Install rsync if not already

apt-get install rsync

Run the script for initial copy

/opt/bin/letsencrypt-sync.sh

Make the converted certificate readable for everyone

chmod +r /opt/bin/fullchain_and_key.p12

Create a crontab for automatic copy

vi /etc/cron.d/letsencrypt-sync

And add this to the file:

0 1 * * * root /opt/bin/letsencrypt-sync.sh

Configure Tomcat

Enable encryption by editing /etc/tomcat9/server.xml, uncomment and change appropriately the next section(change password with what you used in script above):

    <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
               maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS"
               keystoreFile="/opt/tomcat-certs/fullchain_and_key.p12" keystoreType="PKCS12"
               keystorePass="<password>"
               />

In the same file, add/modify these lines at the end of the file to let tomcat see the original IP when running behind a reverse proxy

        <Valve className="org.apache.catalina.valves.RemoteIpValve" />

        <!-- Access log processes all example.
             Documentation at: /docs/config/valve.html
             Note: The pattern used is equivalent to using pattern="common" -->
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
                prefix="localhost_access_log" suffix=".txt"
                requestAttributesEnabled="true"
               pattern="%h %l %u %t "%r" %s %b" />

Restart tomcat and you should be able to access it at https://my.domain.com:8443

systemctl restart tomcat9


Add the following argumet to the HTTPS proxy vhost:

SSLProxyEngine On

Install CAS

Download the CAS Overlay Template needed for installation.

mkdir /opt/cas
cd /opt/cas
wget https://github.com/apereo/cas-overlay-template/archive/6.6.zip
unzip 6.6.zip
cd cas-overlay-template-6.6

First, you need to open the file build.gradle and add the necessary dependencies. Here are the base dependencies that you'll most probably need:

dependencies {
    implementation "org.apereo.cas:cas-server-webapp"
    implementation "org.apereo.cas:cas-server-support-ldap"
    implementation "org.apereo.cas:cas-server-support-jdbc"
    implementation "org.apereo.cas:cas-server-support-jdbc-drivers"
    implementation "org.apereo.cas:cas-server-support-json-service-registry"
    implementation "org.apereo.cas:cas-server-support-saml"
    implementation "org.apereo.cas:cas-server-support-oauth-webflow"
    implementation "org.apereo.cas:cas-server-support-oidc"
    implementation "org.apereo.cas:cas-server-support-simple-mfa"
    implementation "org.apereo.cas:cas-server-support-sms-nexmo"
}

For more dependencies like SAML, OAuth2, OpenID Connect, 2 Factor Authentication, etc. check CAS official documentation: https://apereo.github.io/cas/6.6.x/index.html

By default when building CAS, it doesn't make all the resources available, that you need to configure and customize your CAS instance. So you first need to make those resources available for the war file that you'll build.

./gradlew unzip   ### explodeWar was the valid option before CAS 6.5.x instead of unzip
rm -r src/main/resources/*
cp -r build/cas-resources/* src/main/resources/

Note: if you are also building a failover server as well, or you think you'll need to rebuild the app in the future (e.g. to add another dependency) it will be easier to first configure CAS with the resources you just copied and then build it and copy the cas.war into the tomcat folder on all servers needed.

Now we can build the application war file.

./gradlew clean build [-Pvalidate=false]

Move the resulted war file into the tomcat folder

cp build/libs/cas.war /var/lib/tomcat9/webapps/

Note: CAS 6.1 requires tomcat 9.0.27 (or newer), so if you have an older version of tomcat 9 it can still work but this will need to be set in /var/lib/tomcat9/webapps/cas/WEB-INF/classes/application.properties

spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration

To be able to manage what services/apps are allowed to authenticate through CAS, you need to add this line to the configuration

cas.serviceRegistry.initFromJson=true
cas.serviceRegistry.json.location=file:/var/lib/tomcat9/webapps/cas/WEB-INF/classes/services
cas.logout.followServiceRedirects=true

To set the ticket timeout use

cas.ticket.tgt.timeout.maxTimeToLiveInSeconds=43200

If you plan to implement OAuth2 on CAS you should specifically configure the service URL

cas.server.name=https://cas.domain.com
cas.server.prefix=${cas.server.name}/cas
cas.authn.oauth.user-profile-view-type=FLAT

If you plan to implement OIDC on CAS you should set the issuer URL and keystore location

cas.authn.oidc.issuer=https://cas.domain.com/cas/oidc
cas.authn.oidc.jwks.jwks-file=file:/var/lib/tomcat9/webapps/cas/WEB-INF/classes/keystore.jwks

Comment these lines from the configuration to disable the default account.

#cas.authn.accept.enabled=true
#cas.authn.accept.users=casuser::Mellon
#cas.authn.accept.name=Static Credentials

To set an LDAP server as the user source use this configuration

cas.authn.ldap[0].providerClass=org.ldaptive.provider.unboundid.UnboundIDProvider
cas.authn.ldap[0].type=AUTHENTICATED
cas.authn.ldap[0].ldapUrl=ldaps://ldap.domain.com
cas.authn.ldap[0].useSsl=true
cas.authn.ldap[0].useStartTls=false
cas.authn.ldap[0].connectTimeout=5000
cas.authn.ldap[0].minPoolSize=0
cas.authn.ldap[0].baseDn=cn=Users,dc=<domain>,dc=local
cas.authn.ldap[0].searchFilter=sAMAccountName={user}
cas.authn.ldap[0].bindDn=cn=<bind-user>,cn=Users,dc=<domain>,dc=local
cas.authn.ldap[0].bindCredential=<password>
cas.authn.ldap[0].trustCertificates=file:/opt/samba-cert/samba-cert.pem
cas.authn.ldap[0].principalAttributeList=sAMAccountName,mail,displayName

Restart tomcat

systemctl restart tomcat9

Change login page design

To add logo to the login page first copy the .png file /cas/WEB-INF/classes/static/images directory and change the file ownership to tomcat user:

sudo chown tomcat:tomcat logo.png

Add following line to /var/lib/tomcat9/webapps/cas/WEB-INF/classes/templates/fragments/header.html before or after the "svg" tag contained in a <a> tag:

<a href="https://newro.co/"><img src="/cas/images/newroco_logo.png" style="width: 375px;height: 55px;"/></a>

To remove the drop down menu, remove all the

"<div class="collapse navbar-collapse" id="navbarSupportedContent">"

class.

Change the head bar background color

Add following file to /cas/WEB-INF/classes/static/css/cas.css line 11755:

header > .navbar {
background-color: #a1b1b9;
color: #fff;

Change the "Reset password?" button

Edit the text message /cas/WEB-INF/classes/messages.properties line 27 and the redirect link from /cas/WEB-INF/classes/templates/fragments/pmlinks.html line 32.

OAuth2

To be able to use the OAuth2 you first need to add this to the dependencies before building CAS

compile "org.apereo.cas:cas-server-support-oauth-webflow:${project.'cas.version'}"

Now create a json file in /var/lib/tomcat9/webapps/cas/WEB-INF/classes/services/ to allow an app to authenticate with CAS using the OAuth2 protocol

{
  "@class" : "org.apereo.cas.support.oauth.services.OAuthRegisteredService",
  "clientId": "OAuth2AppToBeAllowed",
  "clientSecret": "<secret>",  ### can be generated with "openssl rand -base64 32"
  "serviceId" : "^https://app.domain.com/path/to/OAuth2/endpoint",
  "name" : "OAuth for my App",
  "id" : 10000002,   ### make sure this id is unique
  "attributeReleasePolicy" : {
    "@class" : "org.apereo.cas.services.ReturnAllowedAttributeReleasePolicy",
    "allowedAttributes" : [ "java.util.ArrayList", [ "sAMAccountName", "mail", "displayName" ] ]
  },
  "bypassApprovalPrompt" : true,  ### this is needed so the user won't be asked at every login if he wants to allow the App to use the info provided by CAS
  "evaluationOrder" : 102
}

Troubleshooting

In case you need to see how the response from CAS looks like, here is how you can find out. First install jq

apt-get install jq

Request a token from CAS

curl https://cas.domain.com/cas/oauth2.0/token?grant_type=password'&'client_id=client'&'client_secret=secret'&'username=my.user'&'password=my-password | jq

Then request the info about the user with the received token

curl -k --user client:secret https://cas.domain.com/cas/oauth2.0/profile?access_token=AT-1-wiNsTgaHzXLUIyaaoFoip-znohWPihea | jq

Enable debug mode

logging.level.org.apereo.cas=DEBUG

2 Factor Authentication (2FA)

Note: CAS calls 2 Factor Authentication (2FA) as Multifactor Authentication (MFA). Mainly because it is possible to set multiple 2FA options in a certain order (e.g. user/pass -> 2fa sms -> 2fa email -> successful login)

Email

To be able to use email 2FA you first need to add this to the dependencies before building CAS

compile "org.apereo.cas:cas-server-support-simple-mfa:${project.'cas.version'}"

Next you need to install postfix

apt-get install postfix

Add these lines to the CAS config in /var/lib/tomcat9/webapps/cas/WEB-INF/classes/application.properties

cas.authn.mfa.globalProviderId=mfa-simple
cas.authn.mfa.simple.name=Email MFA
cas.authn.mfa.simple.order=1
cas.authn.mfa.simple.timeToKillInSeconds=180
cas.authn.mfa.simple.tokenLength=6

cas.authn.mfa.simple.mail.from=no-reply@my.domain.com
cas.authn.mfa.simple.mail.text=This is your 2FA code for CAS authentication: %s
cas.authn.mfa.simple.mail.subject=CAS 2FA Code
cas.authn.mfa.simple.mail.validateAddresses=false
cas.authn.mfa.simple.mail.html=false

cas.authn.mfa.simple.mail.attributeName=mail

spring.mail.host=localhost
spring.mail.port=25
spring.mail.testConnection=true
spring.mail.properties.mail.smtp.auth=false
spring.mail.properties.mail.smtp.starttls.enable=false

SMS (Nexmo)

To be able to use SMS 2FA you first need to add this to the dependencies before building CAS

compile "org.apereo.cas:cas-server-support-simple-mfa:${project.'cas.version'}"
compile "org.apereo.cas:cas-server-support-sms-nexmo:${project.'cas.version'}"

Create an account on Nexmo (https://dashboard.nexmo.com/sign-up). After that create a new application, that should give you an api key and a secret.

Add these lines to the CAS config in /var/lib/tomcat9/webapps/cas/WEB-INF/classes/application.properties

cas.authn.ldap[0].principalAttributeList=mail,telephoneNumber   #you probably have this already in your config just need to add the phone attribute

cas.authn.mfa.globalProviderId=mfa-simple
cas.authn.mfa.simple.name=SMS 2FA
cas.authn.mfa.simple.order=1
cas.authn.mfa.simple.timeToKillInSeconds=180
cas.authn.mfa.simple.tokenLength=6

cas.authn.mfa.simple.sms.from=CAS
cas.authn.mfa.simple.sms.text=This is your CAS 2FA code: %s
cas.authn.mfa.simple.sms.attributeName=telephoneNumber

cas.smsProvider.nexmo.apiToken=<api-key>
cas.smsProvider.nexmo.apiSecret=<api-secret>

Signal

To be able to send Signal messages we'll use this project: https://github.com/bbernhard/signal-cli-rest-api/

First install docker. NOTE: this docker repo is for Ubuntu 20.04

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
apt-get install docker-ce

Build and run the docker container for the Signal API

docker run -d --name signal-api --restart=always -p 127.0.0.1:5000:8080 -v /opt/signal-container-config/signal-cli:/home/.local/share/signal-cli -e 'MODE=json-rpc' bbernhard/signal-cli-rest-api

Register(1) a phone number for the API or link(2) it as a new device with a pre-registered number

1.Go to https://signalcaptchas.org/registration/generate.html, open the developer console on the network tab, solve the captcha and then check the failed redirect to signalcaptcha://<captcha-string>. Copy the <captcha-string> after signalcaptcha:// as you'll need it at the next step.

Register the phone number you want to use for the Signal API

curl -X POST 'http://localhost:5000/v1/register/+40712345678' -H 'accept: application/json' -H 'Content-Type: application/json' -d '{"use_voice": false, "captcha": "<captcha-string>"}'

Now you should receive a SMS with the verification code on the phone number you just registered and have to send it to the Signal API

curl -X POST 'http://localhost:5000/v1/register/+40712345678/verify/<sms-code>' -H 'accept: application/json' -H 'Content-Type: application/json'

2.Install these packages that help view a qrcode at CLI

apt-get install zbar-tools qrencode

Get the QR code from the Signal API

wget http://localhost:5000/v1/qrcodelink?device_name=<server-name> -O /tmp/signal-qrcode.png && zbarimg -q --raw /tmp/signal-qrcode.png | tr -d '\n' | qrencode -l H -t utf8 && rm /tmp/signal-qrcode.png

On the device with Signal already set, open the app, click account avatar, click Linked devices, add new device and scan the QR code you get with the above command.

Now you should be able to send Signal messages (with either of the above methods) from your server

curl -X POST  -d '{"message": "test message from server", "number": "+40712345678", "recipients": [ "+40712345678" ]}' http://localhost:5000/v2/send

If you can't send a message to more then 2 different phone numbers, then you need to enter the docker container and run some commands

# su signal-api
# signal-cli -u <phone-number-to-send-from> send -m "test message from cas-test2" <destination-phone-number-that-failed>
Failed to send (some) messages:
+40712345678: CAPTCHA proof required for sending to "+40712345678", available options "PUSH_CHALLENGE, RECAPTCHA" with challenge token "8dbe5d53-xxxx-xxxx-xxxx-eeeb1e8336e0", or wait "86400" seconds.
To get the captcha token, go to https://signalcaptchas.org/challenge/generate.html
Check the developer tools (F12) console for a failed redirect to signalcaptcha://
Everything after signalcaptcha:// is the captcha token.
Use the following command to submit the captcha token:
signal-cli submitRateLimitChallenge --challenge CHALLENGE_TOKEN --captcha CAPTCHA_TOKEN
# signal-cli submitRateLimitChallenge --challenge 8dbe5d53-xxxx-xxxx-xxxx-eeeb1e8336e0 --captcha signal-recaptcha-v2.6LfBXs...


For CAS you'll need this module added when building

implementation "org.apereo.cas:cas-server-support-simple-mfa"

Create a file for the following groovy script:

#vi /opt/cas-groovy-scripts/sendSignalMessage.groovy

import java.util.*

def run(Object[] args) {
    def from = args[0]
    def to = args[1]
    def message = args[2]
    def logger = args[3]

    ["curl", "-X", "POST", "-d", "{\"message\": \"${message}\", \"number\": \"+40712345678\", \"recipients\": [ \"${to}\" ]}", "http://localhost:5000/v2/send"].execute()
    return true
}

Make it accessible to tomcat

chown -R tomcat:tomcat /opt/cas-groovy-scripts

Add these CAS config lines in `/var/lib/tomcat9/webapps/cas/WEB-INF/classes/application.properties`

##
# Signal 2FA
#
cas.authn.mfa.triggers.global.global-provider-id=mfa-simple

cas.authn.mfa.simple.name=Signal 2FA
cas.authn.mfa.simple.order=0
cas.authn.mfa.simple.time-to-kill-in-seconds=180
cas.authn.mfa.simple.token-length=6

cas.authn.mfa.simple.sms.from=CAS
cas.authn.mfa.simple.sms.text=This is your CAS 2FA code: %s. The CASMFA- prefix can be excluded.
cas.authn.mfa.simple.sms.attribute-name=telephoneNumber

cas.sms-provider.groovy.location=file:/opt/cas-groovy-scripts/sendSignalMessage.groovy

And of course, make sure to retrieve attribute telephoneNumber from LDAP or what user source you use.

Trusted numbers

List trusted numbers

curl -X GET http://localhost:5000/v1/identities/<sending-number>

Trust a number (untested)

curl -X PUT -d '{"trust_all_known_keys": false, "verified_safety_number": "string"}' http://localhost:5000/v1/identities/<sending-number>/trust/<receiving-number>

Internal DNS records

If the CAS server and other web services that use CAS for authentication are behind the same proxy they will probably need internal DNS records pointing to the internal IP of the proxy to avoid loops in the firewall routing.

Failover

If you want to have a failover CAS build a second server exactly as above and configure a floating IP with Keepalived as below.

Keepalived

To setup keepalived, install it on both servers:

sudo apt-get install keepalived

Copy the nagios check "check_http" to /usr/local/bin, from the /usr/lib/nagios/plugins of a server that has nagios-plugins installed (please don't install nagios-plugins on the CAS servers, that package would install many dependencies).

Finally create the following /etc/keepalived/keepalived.conf on the master:

global_defs {
        notification_email {
                <email>
        }

        notification_email_from <email>
        smtp_server 127.0.0.1
}

vrrp_script chk_apache {
        script "check_http -S -H 127.0.0.1 -u /cas/ -p 8443"
        interval 3                      # check every 3 seconds
        weight 2                        # add 2 points of prio if OK
}

vrrp_instance floating_ip {
        interface ens3
        state MASTER
        virtual_router_id 31
        priority 101
        authentication {
            auth_type PASS
            auth_pass justatestpass
        }
        virtual_ipaddress {
                <floating-IP>
        }

        track_script {
            chk_apache
        }
}

Create exactly the same file on the failover CAS, just change priority from 101 to 100.

Restart keepalived

service keepalived restart