123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473 |
- [[appendices]]
- = Appendices
- :figures: servlet/authentication/kerberos
- :numbered!:
- [appendix]
- == Material Used in this Document
- Dummy UserDetailsService used in samples because we don't have a real
- user source.
- [source,java,indent=0]
- ----
- include::example$kerberos/DummyUserDetailsService.java[tags=snippetA]
- ----
- [appendix]
- == Crash Course to Kerberos
- In any authentication process there are usually a three parties
- involved.
- image::{figures}/drawio-kerb-cc1.png[]
- First is a `client` which sometimes is a client computer but in most
- of the scenarios it is the actual user sitting on a computer and
- trying to access resources. Then there is the `resource` user is trying
- to access. In this example it is a web server.
- Then there is a `Key Distribution Center` or `KDC`. In a case of
- Windows environment this would be a `Domain Controller`. `KDC` is the
- one which really brings everything together and thus is the most
- critical component in your environment. Because of this it is also
- considered as a single point of failure.
- Initially when `Kerberos` environment is setup and domain user
- principals created into a database, encryption keys are also
- created. These encryption keys are based on shared secrets(i.e. user
- password) and actual passwords are never kept in a clear text.
- Effectively `KDC` has its own key and other keys for domain users.
- Interestingly there is no communication between a `resource` and a
- `KDC` during the authentication process.
- image::{figures}/drawio-kerb-cc2.png[]
- When client wants to authenticate itself with a `resource` it first
- needs to communicate with a `KDC`. `Client` will craft a special package
- which contains encrypted and unencrypted parts. Unencrypted part
- contains i.e. information about a user and encrypted part other
- information which is part of a protocol. `Client` will encrypt package
- data with its own key.
- When `KDC` receives this authentication package from a client it
- checks who this `client` claims to be from an unencrypted part and based
- on that information it uses `client` decryption key it already have in
- its database. If this decryption is succesfull `KDC` knows that this
- `client` is the one it claims to be.
- What KDC returns to a client is a ticket called `Ticket Granting
- Ticket` which is signed by a KDC's own private key. Later when
- `client` sends back this ticket it can try to decrypt it and if that
- operation is succesfull it knows that it was a ticket it itself
- originally signed and gave to a `client`.
- image::{figures}/drawio-kerb-cc3.png[]
- When client wants to get a ticket which it can use to authenticate
- with a service, `TGT` is sent to `KDC` which then signs a service ticket
- with service's own key. This a moment when a trust between
- `client` and `service` is created. This service ticket contains data
- which only `service` itself is able to decrypt.
- image::{figures}/drawio-kerb-cc4.png[]
- When `client` is authenticating with a service it sends previously
- received service ticket to a service which then thinks that I don't
- know anything about this guy but he gave me an authentication ticket.
- What `service` can do next is try to decrypt that ticket and if that
- operation is succesfull it knows that only other party who knows my
- credentials is the `KDC` and because I trust him I can also trust that
- this client is a one he claims to be.
- [appendix]
- == Setup Kerberos Environments
- Doing a production setup of Kerberos environment is out of scope of
- this document but this appendix provides some help to get you
- started for setting up needed components for development.
- [[setupmitkerberos]]
- === Setup MIT Kerberos
- First action is to setup a new realm and a database.
- [source,text,indent=0]
- ----
- # kdb5_util create -s -r EXAMPLE.ORG
- Loading random data
- Initializing database '/var/lib/krb5kdc/principal' for realm 'EXAMPLE.ORG',
- master key name 'K/M@EXAMPLE.ORG'
- You will be prompted for the database Master Password.
- It is important that you NOT FORGET this password.
- Enter KDC database master key:
- Re-enter KDC database master key to verify:
- ----
- `kadmin` command can be used to administer Kerberos environment but
- you can't yet use it because there are no admin users in a database.
- [source,text,indent=0]
- ----
- root@neo:/etc/krb5kdc# kadmin
- Authenticating as principal root/admin@EXAMPLE.ORG with password.
- kadmin: Client not found in Kerberos database while initializing
- kadmin interface
- ----
- Lets use `kadmin.local` command to create one.
- [source,text,indent=0]
- ----
- root@neo:/etc/krb5kdc# kadmin.local
- Authenticating as principal root/admin@EXAMPLE.ORG with password.
- kadmin.local: listprincs
- K/M@EXAMPLE.ORG
- kadmin/admin@EXAMPLE.ORG
- kadmin/changepw@EXAMPLE.ORG
- kadmin/cypher@EXAMPLE.ORG
- krbtgt/EXAMPLE.ORG@EXAMPLE.ORG
- kadmin.local: addprinc root/admin@EXAMPLE.ORG
- WARNING: no policy specified for root/admin@EXAMPLE.ORG; defaulting to
- no policy
- Enter password for principal "root/admin@EXAMPLE.ORG":
- Re-enter password for principal "root/admin@EXAMPLE.ORG":
- Principal "root/admin@EXAMPLE.ORG" created.
- ----
- Then enable admins by modifying `kadm5.acl` file and restart Kerberos
- services.
- [source,text,indent=0]
- ----
- # cat /etc/krb5kdc/kadm5.acl
- # This file Is the access control list for krb5 administration.
- */admin *
- ----
- Now you can use `kadmin` with previously created `root/admin`
- principal. Lets create our first user `user1`.
- [source,text,indent=0]
- ----
- kadmin: addprinc user1
- WARNING: no policy specified for user1@EXAMPLE.ORG; defaulting to no
- policy
- Enter password for principal "user1@EXAMPLE.ORG":
- Re-enter password for principal "user1@EXAMPLE.ORG":
- Principal "user1@EXAMPLE.ORG" created.
- ----
- Lets create our second user `user2` and export a keytab file.
- [source,text,indent=0]
- ----
- kadmin: addprinc user2
- WARNING: no policy specified for user2@EXAMPLE.ORG; defaulting to no
- policy
- Enter password for principal "user2@EXAMPLE.ORG":
- Re-enter password for principal "user2@EXAMPLE.ORG":
- Principal "user2@EXAMPLE.ORG" created.
- kadmin: ktadd -k /tmp/user2.keytab user2@EXAMPLE.ORG
- Entry for principal user2@EXAMPLE.ORG with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/tmp/user2.keytab.
- Entry for principal user2@EXAMPLE.ORG with kvno 2, encryption type arcfour-hmac added to keytab WRFILE:/tmp/user2.keytab.
- Entry for principal user2@EXAMPLE.ORG with kvno 2, encryption type des3-cbc-sha1 added to keytab WRFILE:/tmp/user2.keytab.
- Entry for principal user2@EXAMPLE.ORG with kvno 2, encryption type des-cbc-crc added to keytab WRFILE:/tmp/user2.keytab.
- ----
- Lets create a service ticket for tomcat and export credentials to a
- keytab file named `tomcat.keytab`.
- [source,text,indent=0]
- ----
- kadmin: addprinc -randkey HTTP/neo.example.org@EXAMPLE.ORG
- WARNING: no policy specified for HTTP/neo.example.org@EXAMPLE.ORG;
- defaulting to no policy
- Principal "HTTP/neo.example.org@EXAMPLE.ORG" created.
- kadmin: ktadd -k /tmp/tomcat.keytab HTTP/neo.example.org@EXAMPLE.ORG
- Entry for principal HTTP/neo.example.org@EXAMPLE.ORG with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/tmp/tomcat2.keytab.
- Entry for principal HTTP/neo.example.org@EXAMPLE.ORG with kvno 2, encryption type arcfour-hmac added to keytab WRFILE:/tmp/tomcat2.keytab.
- Entry for principal HTTP/neo.example.org@EXAMPLE.ORG with kvno 2, encryption type des3-cbc-sha1 added to keytab WRFILE:/tmp/tomcat2.keytab.
- Entry for principal HTTP/neo.example.org@EXAMPLE.ORG with kvno 2, encryption type des-cbc-crc added to keytab WRFILE:/tmp/tomcat2.keytab.
- ----
- [[setupwinkerberos]]
- === Setup Windows Domain Controller
- This was tested using `Windows Server 2012 R2`
- [TIP]
- ====
- Internet is full of good articles and videos how to setup Windows AD
- but these two are quite usefull
- http://www.rackspace.com/knowledge_center/article/installing-active-directory-on-windows-server-2012[Rackspace] and
- http://social.technet.microsoft.com/wiki/contents/articles/12370.windows-server-2012-set-up-your-first-domain-controller-step-by-step.aspx[Microsoft
- Technet].
- ====
- - Normal domain controller and active directory setup was done.
- - Used dns domain `example.org` and windows domain `EXAMPLE`.
- - I created various domain users like `user1`, `user2`, `user3`,
- `tomcat` and set passwords to `Password#`.
- I eventually also added all ip's of my vm's to AD's dns server for
- that not to cause any trouble.
- [source,text]
- ----
- Name: WIN-EKBO0EQ7TS7.example.org
- Address: 172.16.101.135
- Name: win8vm.example.org
- Address: 172.16.101.136
- Name: neo.example.org
- Address: 172.16.101.1
- ----
- Service Principal Name(SPN) needs to be setup with `HTTP` and a
- server name `neo.example.org` where tomcat servlet container is run. This
- is used with `tomcat` domain user and its `keytab` is then used as a
- service credential.
- [source,text]
- ----
- PS C:\> setspn -A HTTP/neo.example.org tomcat
- ----
- I exported keytab file which is copied to linux server running tomcat.
- [source,text]
- ----
- PS C:\> ktpass /out c:\tomcat.keytab /mapuser tomcat@EXAMPLE.ORG /princ HTTP/neo.example.org@EXAMPLE.ORG /pass Password# /ptype KRB5_NT_PRINCIPAL /crypto All
- Targeting domain controller: WIN-EKBO0EQ7TS7.example.org
- Using legacy password setting method
- Successfully mapped HTTP/neo.example.org to tomcat.
- ----
- [appendix]
- == Troubleshooting
- This appendix provides generic information about troubleshooting
- errors and problems.
- [IMPORTANT]
- ====
- If you think environment and configuration is correctly setup, do
- double check and ask other person to check possible obvious mistakes
- or typos. Kerberos setup is generally very brittle and it is not
- always very easy to debug where the problem lies.
- ====
- .Cannot find key of appropriate type to decrypt
- [source,text]
- ----
- GSSException: Failure unspecified at GSS-API level (Mechanism level:
- Invalid argument (400) - Cannot find key of appropriate type to
- decrypt AP REP - RC4 with HMAC)
- ----
- If you see abore error indicating missing key type, this will happen
- with two different use cases. Firstly your JVM may not support
- appropriate encryption type or it is disabled in your `krb5.conf`
- file.
- [source,text]
- ----
- default_tkt_enctypes = rc4-hmac
- default_tgs_enctypes = rc4-hmac
- ----
- Second case is less obvious and hard to track because it will lead
- into same error. This specific `GSSException` is throws also if you
- simply don't have a required encryption key which then may be caused
- by a misconfiguration in your kerberos server or a simply typo in your
- principal.
- .Using wrong kerberos configuration
- {zwsp} +
- In most system all commands and libraries will search kerberos
- configuration either from a default locations or special locations
- like JDKs. It's easy to get mixed up especially if working from unix
- systems, which already may have default settings to work with MIT
- kerberos, towards Windows domains.
- This is a specific example what happens with `ldapsearch` trying to
- query Windows AD using kerberos authentication.
- [source,text]
- ----
- $ ldapsearch -H ldap://WIN-EKBO0EQ7TS7.example.org -b "dc=example,dc=org"
- SASL/GSSAPI authentication started
- ldap_sasl_interactive_bind_s: Local error (-2)
- additional info: SASL(-1): generic failure: GSSAPI Error:
- Unspecified GSS failure. Minor code may provide more information
- (No Kerberos credentials available)
- ----
- Well that doesn't look good and is a simple indication that I don't
- have a valid kerberos tickets as shown below.
- [source,text]
- ----
- $ klist
- klist: Credentials cache file '/tmp/krb5cc_1000' not found
- ----
- We already have a keytab file we exported from Windows AD to be used
- with tomcat running on Linux. Lets try to use that to authenticate
- with Windows AD.
- You can have a dedicated config file which usually can be used with
- native Linux commands and JVMs via system propertys.
- [source,text]
- ----
- $ cat krb5.ini
- [libdefaults]
- default_realm = EXAMPLE.ORG
- default_keytab_name = /tmp/tomcat.keytab
- forwardable=true
- [realms]
- EXAMPLE.ORG = {
- kdc = WIN-EKBO0EQ7TS7.example.org:88
- }
- [domain_realm]
- example.org=EXAMPLE.ORG
- .example.org=EXAMPLE.ORG
- ----
- Lets use that config and a keytab to get initial credentials.
- [source,text]
- ----
- $ env KRB5_CONFIG=/path/to/krb5.ini kinit -kt tomcat.keytab HTTP/neo.example.org@EXAMPLE.ORG
- $ klist
- Ticket cache: FILE:/tmp/krb5cc_1000
- Default principal: HTTP/neo.example.org@EXAMPLE.ORG
- Valid starting Expires Service principal
- 26/03/15 09:04:37 26/03/15 19:04:37 krbtgt/EXAMPLE.ORG@EXAMPLE.ORG
- renew until 27/03/15 09:04:37
- ----
- Lets see what happens if we now try to do a simple query against
- Windows AD.
- [source,text]
- ----
- $ ldapsearch -H ldap://WIN-EKBO0EQ7TS7.example.org -b "dc=example,dc=org"
- SASL/GSSAPI authentication started
- ldap_sasl_interactive_bind_s: Local error (-2)
- additional info: SASL(-1): generic failure: GSSAPI Error:
- Unspecified GSS failure. Minor code may provide more information
- (KDC returned error string: PROCESS_TGS)
- ----
- This may be simply because `ldapsearch` is getting confused and simply
- using wrong configuration. You can tell `ldapsearch` to use a
- different configuration via `KRB5_CONFIG` env variable just like we
- did with `kinit`. You can also use `KRB5_TRACE=/dev/stderr` to get
- more verbose output of what native libraries are doing.
- [source,text]
- ----
- $ env KRB5_CONFIG=/path/to/krb5.ini ldapsearch -H ldap://WIN-EKBO0EQ7TS7.example.org -b "dc=example,dc=org"
- $ klist
- Ticket cache: FILE:/tmp/krb5cc_1000
- Default principal: HTTP/neo.example.org@EXAMPLE.ORG
- Valid starting Expires Service principal
- 26/03/15 09:11:03 26/03/15 19:11:03 krbtgt/EXAMPLE.ORG@EXAMPLE.ORG
- renew until 27/03/15 09:11:03
- 26/03/15 09:11:44 26/03/15 19:11:03
- ldap/win-ekbo0eq7ts7.example.org@EXAMPLE.ORG
- renew until 27/03/15 09:11:03
- ----
- Above you can see what happened if query was successful by looking
- kerberos tickets. Now you can experiment with further query commands
- i.e. if you working with `KerberosLdapContextSource`.
- [source,text]
- ----
- $ ldapsearch -H ldap://WIN-EKBO0EQ7TS7.example.org \
- -b "dc=example,dc=org" \
- "(| (userPrincipalName=user2@EXAMPLE.ORG)
- (sAMAccountName=user2@EXAMPLE.ORG))" \
- dn
- ...
- # test user, example.org
- dn: CN=test user,DC=example,DC=org
- ----
- [appendix]
- [[browserspnegoconfig]]
- == Configure Browsers for Spnego Negotiation
- === Firefox
- Complete following steps to ensure that your Firefox browser is
- enabled to perform Spnego authentication.
- - Open Firefox.
- - At address field, type *about:config*.
- - In filter/search, type *negotiate*.
- - Parameter *network.negotiate-auth.trusted-uris* may be set to
- default *https://* which doesn't work for you. Generally speaking
- this parameter has to replaced with the server address if Kerberos
- delegation is required.
- - It is recommended to use `https` for all communication.
- === Chrome
- With Google Chrome you generally need to set command-line parameters
- order to white list servers with Chrome will negotiate.
- - on Windows machines (clients): Chrome shares the configuration with
- Internet Explorer so if all changes were applied to IE (as described
- in E.3), nothing has to be passed via command-line parameters.
- - on Linux/Mac OS machines (clients): the command-line parameter
- `--auth-negotiate-delegate-whitelist` should only used if Kerberos
- delegation is required (otherwise do not set this parameter).
- - It is recommended to use `https` for all communication.
- [source,text]
- ----
- --auth-server-whitelist="*.example.com"
- --auth-negotiate-delegate-whitelist="*.example.com"
- ----
- You can see which policies are enable by typing *chrome://policy/*
- into Chrome's address bar.
- With Linux Chrome will also read policy files from
- `/etc/opt/chrome/policies/managed` directory.
- .mypolicy.json
- [source,json]
- ----
- {
- "AuthServerWhitelist" : "*.example.org",
- "AuthNegotiateDelegateWhitelist" : "*.example.org",
- "DisableAuthNegotiateCnameLookup" : true,
- "EnableAuthNegotiatePort" : true
- }
- ----
- === Internet Explorer
- Complete following steps to ensure that your Internet Explorer browser
- is enabled to perform Spnego authentication.
- - Open Internet Explorer.
- - Click *Tools > Intenet Options > Security* tab.
- - In *Local intranet* section make sure your server is trusted by i.e.
- adding it into a list.
|