From a8f2514dd1ff014770f2cce277740a0408857f14 Mon Sep 17 00:00:00 2001 From: AngusWarren Date: Tue, 31 May 2016 14:28:48 +0800 Subject: [PATCH] Initial commit of RemoteUserJiraAuth 1.1 --- .gitignore | 4 + README.md | 65 +++++++++++++++ RemoteUserJiraAuth/LICENSE | 13 +++ RemoteUserJiraAuth/pom.xml | 75 ++++++++++++++++++ .../anguswarren/jira/RemoteUserJiraAuth.java | 66 +++++++++++++++ .../src/main/resources/atlassian-plugin.xml | 7 ++ builds/RemoteUserJiraAuth-1.1.jar | Bin 0 -> 2095 bytes builds/RemoteUserJiraAuth-1.1.tar.gz | Bin 0 -> 2166 bytes examples/jira_proxy.conf | 71 +++++++++++++++++ examples/krb5.conf | 24 ++++++ examples/smb.conf | 13 +++ 11 files changed, 338 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 RemoteUserJiraAuth/LICENSE create mode 100644 RemoteUserJiraAuth/pom.xml create mode 100644 RemoteUserJiraAuth/src/main/java/anguswarren/jira/RemoteUserJiraAuth.java create mode 100644 RemoteUserJiraAuth/src/main/resources/atlassian-plugin.xml create mode 100644 builds/RemoteUserJiraAuth-1.1.jar create mode 100644 builds/RemoteUserJiraAuth-1.1.tar.gz create mode 100644 examples/jira_proxy.conf create mode 100644 examples/krb5.conf create mode 100644 examples/smb.conf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0a1009b --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*~ +*.swp +*.swo +target/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..dcb3200 --- /dev/null +++ b/README.md @@ -0,0 +1,65 @@ +JIRA 4.3+ with mod_auth_kerb SSO +================================ +Goal +---- +Users should transparently log in to JIRA with AD domain credentials. + +Overview +-------- +Apache authenticates users using mod_auth_kerb and passes the authenticated username to JIRA through an AJP proxy. JIRA uses a custom Seraph filter which checks for the remote_user variable set by Apache and logs the user in automatically. + +Installation +------------ +1. Install Jira using the standard install, listening on port 8080 + * Allow port 8080 through the firewall +2. Setup LDAP user directory + * Test logging in using your AD credentials +3. Setup apache to act as a proxy to Jira using AJP + * Add this line to the server.xml (/opt/atlassian/jira/conf/server.xml) file, around line 64. It should end up below the existing "Connector" entry. + ```xml + + ``` + * Check the "jira_proxy.conf" file in examples for the apache configuration. +4. Install mod_auth_kerb and configure it to authenticate against your AD + * There is plenty of documentation out there on how to do this, I have also included my configuration files in the examples directory. (krb5.conf and smb.conf) + * Set up a location like /private and test against that. Once Kerberos is authenticating properly there, apply it to the JIRA proxy created in the previous step. +5. Add the jar file (RemoteUserJiraAuth-X.Y.jar) to the WEB-INF/lib/ directory (by default it's /opt/atlassian/jira/atlassian-jira/WEB-INF/lib/) + * Ensure that you've removed any older versions which may exist. +6. Edit WEB-INF/classes/seraph-config.xml and replace the existing authenticator with the custom one: + ```xml + Comment this out: + + Add this below it: + + ``` +7. Restart JIRA and Apache +8. Check to see if it is now working. + +Notes +----- +### Kerberos +Kerberos can be frustrating to configure correctly. Check that DNS is configured correctly, and you have a valid PTR record for the servers IP address. Check that the SPN is valid against the hostname that you are connecting to and that you do not have a duplicate SPN configured in AD. The following code will check for duplicate SPN's +```bash +ldapsearch -h dc01.domain.local -x -W -D "administrator@domain.local" \ +-b "DC=DOMAIN,DC=LOCAL" 'serviceprincipalname=*' serviceprincipalname | \ +grep 'Name:' | sort | uniq -d +``` + +To Generate your keytab, the easiest way is to run this command from the linux host after joining the domain. +``` +net ads keytab add HTTP -U administrator +``` + +If you are using a virtual server and the name you connect with is not the same as the domain computers name, you will need to generate a keytab for the second hostname. At our site, the computer name is Support01 but we are connecting using jira.domain.local. Authentication will fail if the keytab does not match the hostname/fqdn you connect to. To generate a keytab for another hostname: +1. Create a new user account for the SPN/keytab to be bound with, set the password never to expire. +2. From the windows command line run the following command (replace my values to match your environment) + * `ktpass -princ HTTP/jira.domain.local@DOMAIN.LOCAL -out C:\jira.domain.local.keytab -mapuser jira-kerb@domain.local --pass userspassword` +3. Move the keytab to the correct location on the apache host. (specified in the apache config file for your virtual host) + +### Firefox +Open about:config and change add the JIRA fqdn to 'network.negotiate-auth.trusted-uris' + +### Internet Explorer & Chrome +First, add the JIRA fqdn to either the Trusted sites or the Intranet zone. Once you have done that, either + * set the security settings for that zone to allow "automatic logon with the current username and password." + * OR, set the security level for the zone to "Low" diff --git a/RemoteUserJiraAuth/LICENSE b/RemoteUserJiraAuth/LICENSE new file mode 100644 index 0000000..5c94488 --- /dev/null +++ b/RemoteUserJiraAuth/LICENSE @@ -0,0 +1,13 @@ +Copyright 2011 Angus Warren + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/RemoteUserJiraAuth/pom.xml b/RemoteUserJiraAuth/pom.xml new file mode 100644 index 0000000..26c0e22 --- /dev/null +++ b/RemoteUserJiraAuth/pom.xml @@ -0,0 +1,75 @@ + + + + + 4.0.0 + anguswarren.jira + RemoteUserJiraAuth + 1.1 + + + Angus Warren + https://wiki.warren.bz + + + anguswarren.jira.RemoteUserJiraAuth + This is a custom Seraph filter developed by Angus Warren to authenticate based on the remote_user variable set by Apache + atlassian-plugin + + + + com.atlassian.jira + atlassian-jira + ${jira.version} + provided + + + junit + junit + 4.6 + test + + + com.atlassian.jira + jira-func-tests + ${jira.version} + test + + + javax.servlet + servlet-api + 2.4 + provided + + + + + + + com.atlassian.maven.plugins + maven-jira-plugin + 3.4 + true + + ${jira.version} + ${jira.data.version} + + + + maven-compiler-plugin + + 1.6 + 1.6 + + + + + + + 4.3.2 + 4.3 + + + diff --git a/RemoteUserJiraAuth/src/main/java/anguswarren/jira/RemoteUserJiraAuth.java b/RemoteUserJiraAuth/src/main/java/anguswarren/jira/RemoteUserJiraAuth.java new file mode 100644 index 0000000..08ea161 --- /dev/null +++ b/RemoteUserJiraAuth/src/main/java/anguswarren/jira/RemoteUserJiraAuth.java @@ -0,0 +1,66 @@ +/** + * Copyright 2011 Angus Warren + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package anguswarren.jira; + +import org.apache.log4j.Category; +import java.security.Principal; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import com.atlassian.jira.security.login.JiraSeraphAuthenticator; + +public class RemoteUserJiraAuth extends JiraSeraphAuthenticator +{ + private static final Category log = Category.getInstance(RemoteUserJiraAuth.class); + + public Principal getUser(HttpServletRequest request, HttpServletResponse response) + { + Principal user = null; + try + { + if(request.getSession() != null && request.getSession().getAttribute(JiraSeraphAuthenticator.LOGGED_IN_KEY) != null) + { + log.debug("Session found; user already logged in"); + user = (Principal) request.getSession().getAttribute(JiraSeraphAuthenticator.LOGGED_IN_KEY); + } + else + { + log.debug("Trying RemoteUserJiraAuth SSO"); + String remoteuser = request.getRemoteUser(); + log.debug("remote_user set to: " + remoteuser); + if(remoteuser != null) + { + String[] username = remoteuser.split("@"); + user = getUser(username[0]); + log.debug("Logging in with username: " + user); + request.getSession().setAttribute(JiraSeraphAuthenticator.LOGGED_IN_KEY, user); + request.getSession().setAttribute(JiraSeraphAuthenticator.LOGGED_OUT_KEY, null); + } + else + { + log.warn("remote_user is null"); + return null; + } + } + } + catch (Exception e) + { + log.warn("Exception: " + e, e); + } + return user; + } + +} diff --git a/RemoteUserJiraAuth/src/main/resources/atlassian-plugin.xml b/RemoteUserJiraAuth/src/main/resources/atlassian-plugin.xml new file mode 100644 index 0000000..31ae603 --- /dev/null +++ b/RemoteUserJiraAuth/src/main/resources/atlassian-plugin.xml @@ -0,0 +1,7 @@ + + + ${project.description} + ${project.version} + + + diff --git a/builds/RemoteUserJiraAuth-1.1.jar b/builds/RemoteUserJiraAuth-1.1.jar new file mode 100644 index 0000000000000000000000000000000000000000..50afd3ba2c0b25d4b7bf25f2d454bb99437bb2b7 GIT binary patch literal 2095 zcma)-2UHVC8plH~QWgl^C_?BYGzEo=7&?T|1w?_17zqIaBtdDq0*6Xy3(^q~1fp^% z5C~mLfTbNxijc?(1PoF{1qC^ElY4iH`*z>EZ{EB&^XB_zzWL9*@8^u*;RON&+0BkD zY6du9LI7R>(#jnUv2(Q6{W1su@Bo|<0)iY5?*F2j6jECAIb?lJi5s!F<@>b=06!SGPytylyyO-5umt{R= za?4j_v?Etk*8<<+-{QIclZbk95zU5u45xojWUcbYTWGRZQMiBz!c`O=kH+a@1Mw(b zS9C}y5q*|`#@n-}@CYIX>K}|E5K=ut+@w5#*P-BG5kv!5y~Lz+75`5&-rCZZe6NF4 zyyEMpsoQnUYRN-5M*GmvQP#&V@zny*pPc|lwrqi7gb`Sw+1IEY#T)Ov?3XmGy~FuD-I}IJE-4!p#(i$PI;m?-r3;sZ8z=Ya3Y+EQ zqzvF`&(SvT%}TwDKJaG604o_-nN@R-;Xn>EOO#(`B1HWvw$6lfOm8{EI>xsk7L=uI zxt4dueg;vA=h3K4W_R1EkqV8dFN1m(Luh)#vb5{S&WIkkuf6Q=&r2G8^d+FfLO&Ob zo&parVacY3jK-;EHHZE>klx*4LL-nL!T6XMG(taZOzw$S@BMsc_bTh8!k|I#guS_z z1T7Y7HY&SUXGgZOv8Cvsd)urK$7CFm)Jp}KTaU5uUILFkLs2ucSo#z7g8rL5YS66o zrt@=m+ZCvvQs;)aKkOEukk8Iu)zx-iVoonUC$PM$pGw*6-9aPV%Qu>}w9Wbk!=lse zB)}c~cTrc>u$q!D^t;!^nyJ#@#v{KiXFo8X^ig$+C6Cc4t$2D_)Iic`2+Ay)<5*)Ijulmukgq^6P>uGt&5)Oz>NBVy}dXNto8YOeAWWu1>9D zMRMaA9a1XcHz~dv0ZRo9Gqf5WnkdM|=ALV4=$MB{wPK945ujlv3C1u09g~rVo|}&! zsGvO*Y^!X8L*pnuZs&kyK>Y1% zM|gTh$+zfI%X$m~Yh-0q-LoBH{0pN&V|q6FS@=}jKZyJ3vd9OxPc7WUfT_t+AH$76 z+<0`nqZ&*ecITRIXYqKY(9wxGNg>KfyQ(AFFM*CWX?Rv@>MQ|2ZC=;$-14hJf!us& zigEtR32*@`c3l>12sw)>Wd5vlqLy@Yvh~{A*5fqi_>qpXovuTye5%&`kQ(OUMYF(5 zQlVkSh5d&gEPgJ%}e#SbJil=w%ULh$ScJm{gY``A)m{3aqbc zrG=7Wnq)lpTt*+qk+XuOrnd@Mn6&;1#STy8z!jcGbow9ZN z1^O;6eOJ(I{Af|hTm9liW#7yX+Mi6{E6{d9Dv^jB66^d}|B7(bs(MT4gr#W$7uc3u z*p^?f@+b)H+)7~PTD87sHYZ&V4d*KPX)qZKyUjEe!OF$nLW`DsNxkN;00qH?EflBT zB(290OzzYD>3LUJ4um4aBIYk*o7Uh)Hi=Ydu^BTn59^;gZ3wt<~9H-+^rLvW~c|-n^_d6FXzt%sd zH0Np7?L2nL#)|*q)UK5n5zuiZXY&lhMiCrCzf&u+r@Woi>$K${kq}1#B`S*?f5zew z9ec5`%g6KNkmzlJVfsMQhKryHbN$^pJ>KxrScJUP)=ar*!A7| o*u(#uWCyq9e1n7c{V}l#zCZsI&Imq!&f&c5Cc{>VM}RZ?9fj{+%>V!Z literal 0 HcmV?d00001 diff --git a/builds/RemoteUserJiraAuth-1.1.tar.gz b/builds/RemoteUserJiraAuth-1.1.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..3c18029f33276e68f48a0fca18366252fc9a04c8 GIT binary patch literal 2166 zcmV-+2#NO}iwFQ&bw*AA1MOOEZ{s!+&e!Ny@Qk8x_F~EJKI}T~`F7LR*EA{OZ1)yL z5zrFta95UeB;~{n^51VrN!E)k$7!4#4#x-W#v+HqnR&<|MGAYfkl$j)h-ZGG3|nWT z_owIM(}O*t4(PVq>Mx-9w^8pj4jPSav(avMdhO0Zz0t0>dk3h#Pb10@a)B8_2h8`y zHo3>@|3~rO50;G1ZUk!98x1s+!vTF#s)+`e1`Ch5vUWswDXoxLA}{A;{H^?gdv7QxnOh>id=va ztH9H&0E7s8s4^U*(YS*CF&vM^$Hu48)sGh+uh6IA<>m1FYIHhA7nkV$#rcQP)#&0J zp1w!J^Uvs~(fNmCL?ArS3AqcHv>gnjGIYc-jWHp)&ZmB43=fD+r_=_IfLJ^uXyz{n z^S}`l5H_b=lE=X`$8hPK3M|y~nmeZP-yWzMF9KZ5|A9X@@8<44`*lH*i+jk&EoK!wueP8=q<-37l^aJL9A+|su?(vgK zoNVWK0RtzKZhyJ>*=n10P@{6Pf@<>ij?+~$nWJx8szDPr0M@^LJ{yCEIj&I;_<+SA z+nm$4T-BcWwn|VtbdSm;R6%XgzOG-_%{%T?2GQ!#pZgARAynZ89UUbsj%V}-#UTsg`a!hzW}T4hEe6HJ6R;c$f+mr6bw=VuKw$mz zY)W`0maF1rT9_LVu#+)Y>NkyvRf`PysXbAH;<#9~NruEX_lk)4@gXx-a^f6zN@M_& zc0nED^sVSQ^~TD$lN3I|*Ds+*#SZSpa*uk|HoMzB5rm8FUc59@Qmi%&J-a4t;rpg) z2L}&xo*f>hY~TgHGhs?BT#{u4L^4Lk^)(#OyzwBGSk^S#88e}xWE>r?hdxuHCQej1 z38|ZjPd}Ps!FIU(ii1@MPf4Z%LvSo*vds@O^nF^kjeA0V7?RD;@7f4RH)yocc1fP1-x zCCe`)!j{?WTe-4=XqG`KA4}(og?H$jrc#`|8L}fj;XiDL9i?Ttxmnwir)V^^88Qp|MDp3 zUv4V)GYFo}KhR&-{J#bs;XhOT=f}d%`M=wZ&VQQqdRyoJSHTnbSJi)}j~)4MHrl;r zz0s5W_c~3@|7+l>{I4GXnNo0TACH~?c6+@7|D6^L7k&Qw3b5Y1G0+>d?HUlO<^RvU z3Jkz_wY!hwIPUU(EMdkeSbx?-B`_Sxips5Q4ije__X|YFMu*zN^t{?<;9(F>V6Y%twnpnI6RATY zhoce=#=Uxf4;Wp@18^>5ZNo(Iu#1u)A+Q0RtRBr75u^C-q`DzVD^p+=9!8oY`&JP} z&{~RD*TbhK0sK8i8-fLu(T^jg_I`Czk!n^a^(V*+UEnRL7HqlteV;o~q0?&Iq4a1> z)WEAAp}#~b(6`^BP4)6&DB`(PEeWf6cJadxrys6I=hr`-eqQN3${BFKb^-)}HXSkv zXVpsFAIuvV_U|I!u*(Q`6dyB~#?({Eu7EfS)m2=M_U1;uvxnRhaXER!yMl*TY$+%G zhA}%HUu^PBVhk2Tqv&oXb~WQ(s;pX~AY(xGf=Ax#2>&grpuc96m*`Lkf zRc>SYl>P#@?Hg1*Rht=^C&*DrnoF%*2}h*EE{bG~Om)ZRNpGU+2g7)H{#QBW`+rF7 z>g=39`w-{}?|+e8quc2<^!wjyU>E+2cjiz1KIoD6zq&l^&GFxCc6x37{`VT_7s*9m z$?~M~&3$}VWX6}P4`y1FUeG;MkX)~_^70vq<6E#=`ejii`4&Uf)TlT0b9eUXHyf$4 zOzFdh?>bb=^tL@|wdKMcq&){-dWu$Ozko?x2$@?d0(Br^t?t>fKK0io%s_uVsiC2v sp`oFnp`oFnp`oFnp`oFnp`oFnp`oFnp`oFnq46^K4|b-RiU3dm0CEvfs{jB1 literal 0 HcmV?d00001 diff --git a/examples/jira_proxy.conf b/examples/jira_proxy.conf new file mode 100644 index 0000000..e9e99fa --- /dev/null +++ b/examples/jira_proxy.conf @@ -0,0 +1,71 @@ + + ServerName jira.domain.local + ServerAlias jira + ServerAlias it + + RewriteEngine on + RewriteCond %{SERVER_PORT} =80 + RewriteRule ^/(.*) https://jira.domain.local/$1 [L,R] + + + + + ServerName jira.domain.local + ServerAlias jira + + DocumentRoot /opt/atlassian/jira/atlassian-jira + + SSLEngine on + SSLCertificateFile /etc/httpd/secure/jira.domain.local.crt + SSLCertificateKeyFile /etc/httpd/secure/jira.domain.local.key + SSLCertificateChainFile /etc/httpd/secure/startcom.sub.class1.server.ca.pem + SSLCACertificateFile /etc/httpd/secure/startcom.ca.pem + SSLOptions StrictRequire + SSLProtocol all -SSLv2 + + KeepAlive On + + ProxyRequests Off + ProxyPreserveHost On + + + Order deny,allow + Allow from all + + + ProxyPass /images/ ! + ProxyPass /portlets/ ! + ProxyPass /styles/ ! + ProxyPass / ajp://127.0.0.1:8009/ + ProxyPassReverse / ajp://127.0.0.1:8009/ + + RewriteEngine on + RewriteCond %{HTTP_HOST} !^jira\.domain\.com [NC] + RewriteCond %{HTTP_HOST} !^$ + RewriteRule ^/(.*) http://jira.domain.local/$1 [L,R] + + + AuthType Kerberos + AuthName "JIRA Kerberos Login" + KrbMethodNegotiate On + KrbMethodK5Passwd On + KrbAuthRealms DOMAIN.LOCAL + Krb5KeyTab /etc/httpd/secure/jira.domain.local.kerberos.keytab + require valid-user + + SetOutputFilter DEFLATE + SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary + Header append Vary User-Agent env=!dont-vary + + + + AuthType None + Satisfy Any + + + ServerSignature Off + LogLevel warn + HostnameLookups Off + ErrorLog /var/log/httpd/jira_error.log + CustomLog /var/log/httpd/jira_access.log common + diff --git a/examples/krb5.conf b/examples/krb5.conf new file mode 100644 index 0000000..2644216 --- /dev/null +++ b/examples/krb5.conf @@ -0,0 +1,24 @@ +[logging] + default = FILE:/var/log/krb5libs.log + kdc = FILE:/var/log/krb5kdc.log + admin_server = FILE:/var/log/kadmind.log + +[libdefaults] + default_realm = DOMAIN.LOCAL + default_keytab_name = FILE:/etc/krb5.keytab + dns_lookup_realm = false + dns_lookup_kdc = false + ticket_lifetime = 24h + forwardable = yes + +[realms] + DOMAIN.LOCAL = { + kdc = dc01.domain.local:88 + admin_server = dc01.domain.local:749 + default_domain = domain.local + } + +[domain_realm] + .domain.local = DOMAIN.LOCAL + domain.local = DOMAIN.LOCAL + .DOMAIN.LOCAL = DOMAIN.LOCAL diff --git a/examples/smb.conf b/examples/smb.conf new file mode 100644 index 0000000..01176f8 --- /dev/null +++ b/examples/smb.conf @@ -0,0 +1,13 @@ +[global] + workgroup = SATTERLEY + security = user + netbios name = support01 + realm = DOMAIN.LOCAL + password server = dc01.domain.local + use kerberos keytab = yes + security = ADS + encrypt passwords = yes + passdb backend = tdbsam + server string = Samba Server Version %v + log file = /var/log/samba/log.%m + max log size = 50