Produced by Araxis Merge on 11/20/2017 2:15:52 PM GMT Standard Time. See www.araxis.com for information about Merge. This report uses XHTML and CSS2, and is best viewed with a modern standards-compliant browser. For optimum results when printing this report, use landscape orientation and enable printing of background images and colours in your browser.
| # | Location | File | Last Modified |
|---|---|---|---|
| 1 | C:\Merge Test Files\8.0.47\java\org\apache\catalina\authenticator | SpnegoAuthenticator.java | Fri Sep 29 16:53:28 2017 UTC |
| 2 | C:\Merge Test Files\8.5.23\java\org\apache\catalina\authenticator | SpnegoAuthenticator.java | Thu Sep 28 11:32:16 2017 UTC |
| 3 | C:\Merge Test Files\9.0.1\java\org\apache\catalina\authenticator | SpnegoAuthenticator.java | Wed Sep 27 18:33:40 2017 UTC |
| Note: Merge considers the second file to be the common ancestor of the others. | |||
| Description | Between Files 1 and 2 |
Between Files 2 and 3 |
Relative to Common Ancestor |
|||
|---|---|---|---|---|---|---|
| Text Blocks | Lines | Text Blocks | Lines | Text Blocks | Lines | |
| Unchanged | 14 | 968 | 2 | 992 | ||
| Changed | 12 | 24 | 0 | 0 | 12 | 24 |
| Inserted | 1 | 1 | 0 | 0 | 0 | 0 |
| Removed | 0 | 0 | 1 | 1 | 2 | 2 |
| Note: An automatic merge would leave 0 conflict(s). | ||||||
| Whitespace | Consecutive whitespace is treated as a single space |
|---|---|
| Character case | Differences in character case are significant |
| Line endings | Differences in line endings (CR and LF characters) are ignored |
| CR/LF characters | Not shown in the comparison detail |
No regular expressions were active.
| 1 | /* | 1 | /* | 1 | /* | |||||
| 2 | * License d to the A pache Soft ware Found ation (ASF ) under on e or more | 2 | * License d to the A pache Soft ware Found ation (ASF ) under on e or more | 2 | * License d to the A pache Soft ware Found ation (ASF ) under on e or more | |||||
| 3 | * contrib utor licen se agreeme nts. See the NOTICE file dist ributed wi th | 3 | * contrib utor licen se agreeme nts. See the NOTICE file dist ributed wi th | 3 | * contrib utor licen se agreeme nts. See the NOTICE file dist ributed wi th | |||||
| 4 | * this wo rk for add itional in formation regarding copyright ownership. | 4 | * this wo rk for add itional in formation regarding copyright ownership. | 4 | * this wo rk for add itional in formation regarding copyright ownership. | |||||
| 5 | * The ASF licenses this file to You und er the Apa che Licens e, Version 2.0 | 5 | * The ASF licenses this file to You und er the Apa che Licens e, Version 2.0 | 5 | * The ASF licenses this file to You und er the Apa che Licens e, Version 2.0 | |||||
| 6 | * (the "L icense"); you may no t use this file exce pt in comp liance wit h | 6 | * (the "L icense"); you may no t use this file exce pt in comp liance wit h | 6 | * (the "L icense"); you may no t use this file exce pt in comp liance wit h | |||||
| 7 | * the Lic ense. You may obtai n a copy o f the Lice nse at | 7 | * the Lic ense. You may obtai n a copy o f the Lice nse at | 7 | * the Lic ense. You may obtai n a copy o f the Lice nse at | |||||
| 8 | * | 8 | * | 8 | * | |||||
| 9 | * ht tp://www.a pache.org/ licenses/L ICENSE-2.0 | 9 | * ht tp://www.a pache.org/ licenses/L ICENSE-2.0 | 9 | * ht tp://www.a pache.org/ licenses/L ICENSE-2.0 | |||||
| 10 | * | 10 | * | 10 | * | |||||
| 11 | * Unless required b y applicab le law or agreed to in writing , software | 11 | * Unless required b y applicab le law or agreed to in writing , software | 11 | * Unless required b y applicab le law or agreed to in writing , software | |||||
| 12 | * distrib uted under the Licen se is dist ributed on an "AS IS " BASIS, | 12 | * distrib uted under the Licen se is dist ributed on an "AS IS " BASIS, | 12 | * distrib uted under the Licen se is dist ributed on an "AS IS " BASIS, | |||||
| 13 | * WITHOUT WARRANTIE S OR CONDI TIONS OF A NY KIND, e ither expr ess or imp lied. | 13 | * WITHOUT WARRANTIE S OR CONDI TIONS OF A NY KIND, e ither expr ess or imp lied. | 13 | * WITHOUT WARRANTIE S OR CONDI TIONS OF A NY KIND, e ither expr ess or imp lied. | |||||
| 14 | * See the License f or the spe cific lang uage gover ning permi ssions and | 14 | * See the License f or the spe cific lang uage gover ning permi ssions and | 14 | * See the License f or the spe cific lang uage gover ning permi ssions and | |||||
| 15 | * limitat ions under the Licen se. | 15 | * limitat ions under the Licen se. | 15 | * limitat ions under the Licen se. | |||||
| 16 | */ | 16 | */ | 16 | */ | |||||
| 17 | package or g.apache.c atalina.au thenticato r; | 17 | package or g.apache.c atalina.au thenticato r; | 17 | package or g.apache.c atalina.au thenticato r; | |||||
| 18 | 18 | 18 | ||||||||
| 19 | import jav a.io.File; | 19 | import jav a.io.File; | 19 | import jav a.io.File; | |||||
| 20 | import jav a.io.IOExc eption; | 20 | import jav a.io.IOExc eption; | 20 | import jav a.io.IOExc eption; | |||||
| 21 | import jav a.security .Principal ; | 21 | import jav a.security .Principal ; | 21 | import jav a.security .Principal ; | |||||
| 22 | import jav a.security .Privilege dAction; | 22 | import jav a.security .Privilege dAction; | 22 | import jav a.security .Privilege dAction; | |||||
| 23 | import jav a.security .Privilege dActionExc eption; | 23 | import jav a.security .Privilege dActionExc eption; | 23 | import jav a.security .Privilege dActionExc eption; | |||||
| 24 | import jav a.security .Privilege dException Action; | 24 | import jav a.security .Privilege dException Action; | 24 | import jav a.security .Privilege dException Action; | |||||
| 25 | import jav a.util.Lin kedHashMap ; | 25 | import jav a.util.Lin kedHashMap ; | 25 | import jav a.util.Lin kedHashMap ; | |||||
| 26 | import jav a.util.reg ex.Pattern ; | 26 | import jav a.util.reg ex.Pattern ; | 26 | import jav a.util.reg ex.Pattern ; | |||||
| 27 | 27 | 27 | ||||||||
| 28 | import jav ax.securit y.auth.Sub ject; | 28 | import jav ax.securit y.auth.Sub ject; | 28 | import jav ax.securit y.auth.Sub ject; | |||||
| 29 | import jav ax.securit y.auth.log in.LoginCo ntext; | 29 | import jav ax.securit y.auth.log in.LoginCo ntext; | 29 | import jav ax.securit y.auth.log in.LoginCo ntext; | |||||
| 30 | import jav ax.securit y.auth.log in.LoginEx ception; | 30 | import jav ax.securit y.auth.log in.LoginEx ception; | 30 | import jav ax.securit y.auth.log in.LoginEx ception; | |||||
| 31 | import jav ax.servlet .http.Http ServletRes ponse; | 31 | import jav ax.servlet .http.Http ServletRes ponse; | 31 | import jav ax.servlet .http.Http ServletRes ponse; | |||||
| 32 | 32 | 32 | ||||||||
| 33 | import org .apache.ca talina.Lif ecycleExce ption; | 33 | import org .apache.ca talina.Lif ecycleExce ption; | 33 | import org .apache.ca talina.Lif ecycleExce ption; | |||||
| 34 | import org .apache.ca talina.Rea lm; | 34 | import org .apache.ca talina.Rea lm; | 34 | import org .apache.ca talina.Rea lm; | |||||
| 35 | import org .apache.ca talina.con nector.Req uest; | 35 | import org .apache.ca talina.con nector.Req uest; | 35 | import org .apache.ca talina.con nector.Req uest; | |||||
| 36 | import org .apache.ju li.logging .Log; | 36 | import org .apache.ju li.logging .Log; | 36 | import org .apache.ju li.logging .Log; | |||||
| 37 | import org .apache.ju li.logging .LogFactor y; | 37 | import org .apache.ju li.logging .LogFactor y; | 37 | import org .apache.ju li.logging .LogFactor y; | |||||
| 38 | import org .apache.to mcat.util. buf.ByteCh unk; | 38 | import org .apache.to mcat.util. buf.ByteCh unk; | 38 | import org .apache.to mcat.util. buf.ByteCh unk; | |||||
| 39 | import org .apache.to mcat.util. buf.Messag eBytes; | 39 | import org .apache.to mcat.util. buf.Messag eBytes; | 39 | import org .apache.to mcat.util. buf.Messag eBytes; | |||||
| 40 | import org .apache.to mcat.util. codec.bina ry.Base64; | 40 | import org .apache.to mcat.util. codec.bina ry.Base64; | 40 | import org .apache.to mcat.util. codec.bina ry.Base64; | |||||
| 41 | import org .apache.to mcat.util. compat.Jre Vendor; | 41 | import org .apache.to mcat.util. compat.Jre Vendor; | 41 | import org .apache.to mcat.util. compat.Jre Vendor; | |||||
| 42 | import org .ietf.jgss .GSSContex t; | 42 | import org .ietf.jgss .GSSContex t; | 42 | import org .ietf.jgss .GSSContex t; | |||||
| 43 | import org .ietf.jgss .GSSCreden tial; | 43 | import org .ietf.jgss .GSSCreden tial; | 43 | import org .ietf.jgss .GSSCreden tial; | |||||
| 44 | import org .ietf.jgss .GSSExcept ion; | 44 | import org .ietf.jgss .GSSExcept ion; | 44 | import org .ietf.jgss .GSSExcept ion; | |||||
| 45 | import org .ietf.jgss .GSSManage r; | 45 | import org .ietf.jgss .GSSManage r; | 45 | import org .ietf.jgss .GSSManage r; | |||||
| 46 | import org .ietf.jgss .Oid; | 46 | import org .ietf.jgss .Oid; | 46 | import org .ietf.jgss .Oid; | |||||
| 47 | 47 | 47 | ||||||||
| 48 | 48 | |||||||||
| 49 | /** | 49 | /** | 48 | /** | |||||
| 50 | * A SPNEG O authenti cator that uses the SPNEGO/Ker beros supp ort built in to Java | 50 | * A SPNEG O authenti cator that uses the SPNEGO/Ker beros supp ort built in to Java | 49 | * A SPNEG O authenti cator that uses the SPNEGO/Ker beros supp ort built in to Java | |||||
| 51 | * 6. Succ essful Ker beros auth entication depends o n the corr ect config uration of | 51 | * 6. Succ essful Ker beros auth entication depends o n the corr ect config uration of | 50 | * 6. Succ essful Ker beros auth entication depends o n the corr ect config uration of | |||||
| 52 | * multipl e componen ts. If the configura tion is in valid, the error mes sages are | 52 | * multipl e componen ts. If the configura tion is in valid, the error mes sages are | 51 | * multipl e componen ts. If the configura tion is in valid, the error mes sages are | |||||
| 53 | * often c ryptic alt hough a Go ogle searc h will usu ally point you in th e right | 53 | * often c ryptic alt hough a Go ogle searc h will usu ally point you in th e right | 52 | * often c ryptic alt hough a Go ogle searc h will usu ally point you in th e right | |||||
| 54 | * directi on. | 54 | * directi on. | 53 | * directi on. | |||||
| 55 | */ | 55 | */ | 54 | */ | |||||
| 56 | public cla ss SpnegoA uthenticat or extends Authentic atorBase { | 56 | public cla ss SpnegoA uthenticat or extends Authentic atorBase { | 55 | public cla ss SpnegoA uthenticat or extends Authentic atorBase { | |||||
| 57 | 57 | 56 | ||||||||
| 58 | privat e static f inal Log l og = LogFa ctory.getL og(SpnegoA uthenticat or.class); | 58 | privat e static f inal Log l og = LogFa ctory.getL og(SpnegoA uthenticat or.class); | 57 | privat e static f inal Log l og = LogFa ctory.getL og(SpnegoA uthenticat or.class); | |||||
| 59 | privat e static f inal Strin g AUTH_HEA DER_VALUE_ NEGOTIATE = "Negotia te"; | 58 | privat e static f inal Strin g AUTH_HEA DER_VALUE_ NEGOTIATE = "Negotia te"; | |||||||
| 59 | 60 | 59 | ||||||||
| 60 | privat e String l oginConfig Name = Con stants.DEF AULT_LOGIN _MODULE_NA ME; | 61 | privat e String l oginConfig Name = Con stants.DEF AULT_LOGIN _MODULE_NA ME; | 60 | privat e String l oginConfig Name = Con stants.DEF AULT_LOGIN _MODULE_NA ME; | |||||
| 61 | public String ge tLoginConf igName() { | 62 | public String ge tLoginConf igName() { | 61 | public String ge tLoginConf igName() { | |||||
| 62 | re turn login ConfigName ; | 63 | re turn login ConfigName ; | 62 | re turn login ConfigName ; | |||||
| 63 | } | 64 | } | 63 | } | |||||
| 64 | public void setL oginConfig Name(Strin g loginCon figName) { | 65 | public void setL oginConfig Name(Strin g loginCon figName) { | 64 | public void setL oginConfig Name(Strin g loginCon figName) { | |||||
| 65 | th is.loginCo nfigName = loginConf igName; | 66 | th is.loginCo nfigName = loginConf igName; | 65 | th is.loginCo nfigName = loginConf igName; | |||||
| 66 | } | 67 | } | 66 | } | |||||
| 67 | 68 | 67 | ||||||||
| 68 | privat e boolean storeDeleg atedCreden tial = tru e; | 69 | privat e boolean storeDeleg atedCreden tial = tru e; | 68 | privat e boolean storeDeleg atedCreden tial = tru e; | |||||
| 69 | public boolean i sStoreDele gatedCrede ntial() { | 70 | public boolean i sStoreDele gatedCrede ntial() { | 69 | public boolean i sStoreDele gatedCrede ntial() { | |||||
| 70 | re turn store DelegatedC redential; | 71 | re turn store DelegatedC redential; | 70 | re turn store DelegatedC redential; | |||||
| 71 | } | 72 | } | 71 | } | |||||
| 72 | public void setS toreDelega tedCredent ial( | 73 | public void setS toreDelega tedCredent ial( | 72 | public void setS toreDelega tedCredent ial( | |||||
| 73 | boolean storeDeleg atedCreden tial) { | 74 | boolean storeDeleg atedCreden tial) { | 73 | boolean storeDeleg atedCreden tial) { | |||||
| 74 | th is.storeDe legatedCre dential = storeDeleg atedCreden tial; | 75 | th is.storeDe legatedCre dential = storeDeleg atedCreden tial; | 74 | th is.storeDe legatedCre dential = storeDeleg atedCreden tial; | |||||
| 75 | } | 76 | } | 75 | } | |||||
| 76 | 77 | 76 | ||||||||
| 77 | privat e Pattern noKeepAliv eUserAgent s = null; | 78 | privat e Pattern noKeepAliv eUserAgent s = null; | 77 | privat e Pattern noKeepAliv eUserAgent s = null; | |||||
| 78 | public String ge tNoKeepAli veUserAgen ts() { | 79 | public String ge tNoKeepAli veUserAgen ts() { | 78 | public String ge tNoKeepAli veUserAgen ts() { | |||||
| 79 | Pa ttern p = noKeepAliv eUserAgent s; | 80 | Pa ttern p = noKeepAliv eUserAgent s; | 79 | Pa ttern p = noKeepAliv eUserAgent s; | |||||
| 80 | if (p == nul l) { | 81 | if (p == nul l) { | 80 | if (p == nul l) { | |||||
| 81 | return n ull; | 82 | return n ull; | 81 | return n ull; | |||||
| 82 | } else { | 83 | } else { | 82 | } else { | |||||
| 83 | return p .pattern() ; | 84 | return p .pattern() ; | 83 | return p .pattern() ; | |||||
| 84 | } | 85 | } | 84 | } | |||||
| 85 | } | 86 | } | 85 | } | |||||
| 86 | public void setN oKeepAlive UserAgents (String no KeepAliveU serAgents) { | 87 | public void setN oKeepAlive UserAgents (String no KeepAliveU serAgents) { | 86 | public void setN oKeepAlive UserAgents (String no KeepAliveU serAgents) { | |||||
| 87 | if (noKeepAl iveUserAge nts == nul l || | 88 | if (noKeepAl iveUserAge nts == nul l || | 87 | if (noKeepAl iveUserAge nts == nul l || | |||||
| 88 | noKe epAliveUse rAgents.le ngth() == 0) { | 89 | noKe epAliveUse rAgents.le ngth() == 0) { | 88 | noKe epAliveUse rAgents.le ngth() == 0) { | |||||
| 89 | this.noK eepAliveUs erAgents = null; | 90 | this.noK eepAliveUs erAgents = null; | 89 | this.noK eepAliveUs erAgents = null; | |||||
| 90 | } else { | 91 | } else { | 90 | } else { | |||||
| 91 | this.noK eepAliveUs erAgents = Pattern.c ompile(noK eepAliveUs erAgents); | 92 | this.noK eepAliveUs erAgents = Pattern.c ompile(noK eepAliveUs erAgents); | 91 | this.noK eepAliveUs erAgents = Pattern.c ompile(noK eepAliveUs erAgents); | |||||
| 92 | } | 93 | } | 92 | } | |||||
| 93 | } | 94 | } | 93 | } | |||||
| 94 | 95 | 94 | ||||||||
| 95 | privat e boolean applyJava8 u40Fix = t rue; | 96 | privat e boolean applyJava8 u40Fix = t rue; | 95 | privat e boolean applyJava8 u40Fix = t rue; | |||||
| 96 | public boolean g etApplyJav a8u40Fix() { | 97 | public boolean g etApplyJav a8u40Fix() { | 96 | public boolean g etApplyJav a8u40Fix() { | |||||
| 97 | re turn apply Java8u40Fi x; | 98 | re turn apply Java8u40Fi x; | 97 | re turn apply Java8u40Fi x; | |||||
| 98 | } | 99 | } | 98 | } | |||||
| 99 | public void setA pplyJava8u 40Fix(bool ean applyJ ava8u40Fix ) { | 100 | public void setA pplyJava8u 40Fix(bool ean applyJ ava8u40Fix ) { | 99 | public void setA pplyJava8u 40Fix(bool ean applyJ ava8u40Fix ) { | |||||
| 100 | th is.applyJa va8u40Fix = applyJav a8u40Fix; | 101 | th is.applyJa va8u40Fix = applyJav a8u40Fix; | 100 | th is.applyJa va8u40Fix = applyJav a8u40Fix; | |||||
| 101 | } | 102 | } | 101 | } | |||||
| 102 | 103 | 102 | ||||||||
| 103 | 104 | 103 | ||||||||
| 104 | @Overr ide | 105 | @Overr ide | 104 | @Overr ide | |||||
| 105 | protec ted String getAuthMe thod() { | 106 | protec ted String getAuthMe thod() { | 105 | protec ted String getAuthMe thod() { | |||||
| 106 | re turn Const ants.SPNEG O_METHOD; | 107 | re turn Const ants.SPNEG O_METHOD; | 106 | re turn Const ants.SPNEG O_METHOD; | |||||
| 107 | } | 108 | } | 107 | } | |||||
| 108 | 109 | 108 | ||||||||
| 109 | 110 | 109 | ||||||||
| 110 | @Overr ide | 111 | @Overr ide | 110 | @Overr ide | |||||
| 111 | protec ted void i nitInterna l() throws Lifecycle Exception { | 112 | protec ted void i nitInterna l() throws Lifecycle Exception { | 111 | protec ted void i nitInterna l() throws Lifecycle Exception { | |||||
| 112 | su per.initIn ternal(); | 113 | su per.initIn ternal(); | 112 | su per.initIn ternal(); | |||||
| 113 | 114 | 113 | ||||||||
| 114 | // Kerberos configurat ion file l ocation | 115 | // Kerberos configurat ion file l ocation | 114 | // Kerberos configurat ion file l ocation | |||||
| 115 | St ring krb5C onf = Syst em.getProp erty(Const ants.KRB5_ CONF_PROPE RTY); | 116 | St ring krb5C onf = Syst em.getProp erty(Const ants.KRB5_ CONF_PROPE RTY); | 115 | St ring krb5C onf = Syst em.getProp erty(Const ants.KRB5_ CONF_PROPE RTY); | |||||
| 116 | if (krb5Conf == null) { | 117 | if (krb5Conf == null) { | 116 | if (krb5Conf == null) { | |||||
| 117 | // Syste m property not set, use the To mcat defau lt | 118 | // Syste m property not set, use the To mcat defau lt | 117 | // Syste m property not set, use the To mcat defau lt | |||||
| 118 | File krb 5ConfFile = new File (container .getCatali naBase(), | 119 | File krb 5ConfFile = new File (container .getCatali naBase(), | 118 | File krb 5ConfFile = new File (container .getCatali naBase(), | |||||
| 119 | Constants. DEFAULT_KR B5_CONF); | 120 | Constants. DEFAULT_KR B5_CONF); | 119 | Constants. DEFAULT_KR B5_CONF); | |||||
| 120 | System.s etProperty (Constants .KRB5_CONF _PROPERTY, | 121 | System.s etProperty (Constants .KRB5_CONF _PROPERTY, | 120 | System.s etProperty (Constants .KRB5_CONF _PROPERTY, | |||||
| 121 | krb5ConfFi le.getAbso lutePath() ); | 122 | krb5ConfFi le.getAbso lutePath() ); | 121 | krb5ConfFi le.getAbso lutePath() ); | |||||
| 122 | } | 123 | } | 122 | } | |||||
| 123 | 124 | 123 | ||||||||
| 124 | // JAAS conf iguration file locat ion | 125 | // JAAS conf iguration file locat ion | 124 | // JAAS conf iguration file locat ion | |||||
| 125 | St ring jaasC onf = Syst em.getProp erty(Const ants.JAAS_ CONF_PROPE RTY); | 126 | St ring jaasC onf = Syst em.getProp erty(Const ants.JAAS_ CONF_PROPE RTY); | 125 | St ring jaasC onf = Syst em.getProp erty(Const ants.JAAS_ CONF_PROPE RTY); | |||||
| 126 | if (jaasConf == null) { | 127 | if (jaasConf == null) { | 126 | if (jaasConf == null) { | |||||
| 127 | // Syste m property not set, use the To mcat defau lt | 128 | // Syste m property not set, use the To mcat defau lt | 127 | // Syste m property not set, use the To mcat defau lt | |||||
| 128 | File jaa sConfFile = new File (container .getCatali naBase(), | 129 | File jaa sConfFile = new File (container .getCatali naBase(), | 128 | File jaa sConfFile = new File (container .getCatali naBase(), | |||||
| 129 | Constants. DEFAULT_JA AS_CONF); | 130 | Constants. DEFAULT_JA AS_CONF); | 129 | Constants. DEFAULT_JA AS_CONF); | |||||
| 130 | System.s etProperty (Constants .JAAS_CONF _PROPERTY, | 131 | System.s etProperty (Constants .JAAS_CONF _PROPERTY, | 130 | System.s etProperty (Constants .JAAS_CONF _PROPERTY, | |||||
| 131 | jaasConfFi le.getAbso lutePath() ); | 132 | jaasConfFi le.getAbso lutePath() ); | 131 | jaasConfFi le.getAbso lutePath() ); | |||||
| 132 | } | 133 | } | 132 | } | |||||
| 133 | } | 134 | } | 133 | } | |||||
| 134 | 135 | 134 | ||||||||
| 135 | 136 | 135 | ||||||||
| 136 | @Overr ide | 137 | @Overr ide | 136 | @Overr ide | |||||
| 137 |
p
ubli
c
|
138 | p rote c ted boolean doA uthenticat e(Request request, H ttpServlet Response r esponse) | 137 | protec ted boolea n doAuthen ticate(Req uest reque st, HttpSe rvletRespo nse respon se) | |||||
| 138 | throws I OException { | 139 | throws I OException { | 138 | throws I OException { | |||||
| 139 | 140 | 139 | ||||||||
| 140 | if (checkFor CachedAuth entication (request, response, true)) { | 141 | if (checkFor CachedAuth entication (request, response, true)) { | 140 | if (checkFor CachedAuth entication (request, response, true)) { | |||||
| 141 | return t rue; | 142 | return t rue; | 141 | return t rue; | |||||
| 142 | } | 143 | } | 142 | } | |||||
| 143 | 144 | 143 | ||||||||
| 144 | Me ssageBytes authoriza tion = | 145 | Me ssageBytes authoriza tion = | 144 | Me ssageBytes authoriza tion = | |||||
| 145 | request. getCoyoteR equest().g etMimeHead ers() | 146 | request. getCoyoteR equest().g etMimeHead ers() | 145 | request. getCoyoteR equest().g etMimeHead ers() | |||||
| 146 | .getValu e("authori zation"); | 147 | .getValu e("authori zation"); | 146 | .getValu e("authori zation"); | |||||
| 147 | 148 | 147 | ||||||||
| 148 | if (authoriz ation == n ull) { | 149 | if (authoriz ation == n ull) { | 148 | if (authoriz ation == n ull) { | |||||
| 149 | if (log. isDebugEna bled()) { | 150 | if (log. isDebugEna bled()) { | 149 | if (log. isDebugEna bled()) { | |||||
| 150 | log. debug(sm.g etString(" authentica tor.noAuth Header")); | 151 | log. debug(sm.g etString(" authentica tor.noAuth Header")); | 150 | log. debug(sm.g etString(" authentica tor.noAuth Header")); | |||||
| 151 | } | 152 | } | 151 | } | |||||
| 152 | response .setHeader ("WWW-Auth enticate", "Negotiat e"); | 153 | response .setHeader (AUTH_HEAD ER_NAME, A UTH_HEADER _VALUE_NEG OTIATE); | 152 | response .setHeader (AUTH_HEAD ER_NAME, A UTH_HEADER _VALUE_NEG OTIATE); | |||||
| 153 | response .sendError (HttpServl etResponse .SC_UNAUTH ORIZED); | 154 | response .sendError (HttpServl etResponse .SC_UNAUTH ORIZED); | 153 | response .sendError (HttpServl etResponse .SC_UNAUTH ORIZED); | |||||
| 154 | return f alse; | 155 | return f alse; | 154 | return f alse; | |||||
| 155 | } | 156 | } | 155 | } | |||||
| 156 | 157 | 156 | ||||||||
| 157 | au thorizatio n.toBytes( ); | 158 | au thorizatio n.toBytes( ); | 157 | au thorizatio n.toBytes( ); | |||||
| 158 | By teChunk au thorizatio nBC = auth orization. getByteChu nk(); | 159 | By teChunk au thorizatio nBC = auth orization. getByteChu nk(); | 158 | By teChunk au thorizatio nBC = auth orization. getByteChu nk(); | |||||
| 159 | 160 | 159 | ||||||||
| 160 | if (!authori zationBC.s tartsWithI gnoreCase( "negotiate ", 0)) { | 161 | if (!authori zationBC.s tartsWithI gnoreCase( "negotiate ", 0)) { | 160 | if (!authori zationBC.s tartsWithI gnoreCase( "negotiate ", 0)) { | |||||
| 161 | if (log. isDebugEna bled()) { | 162 | if (log. isDebugEna bled()) { | 161 | if (log. isDebugEna bled()) { | |||||
| 162 | log. debug(sm.g etString( | 163 | log. debug(sm.g etString( | 162 | log. debug(sm.g etString( | |||||
| 163 | "spneg oAuthentic ator.authH eaderNotNe go")); | 164 | "spneg oAuthentic ator.authH eaderNotNe go")); | 163 | "spneg oAuthentic ator.authH eaderNotNe go")); | |||||
| 164 | } | 165 | } | 164 | } | |||||
| 165 | response .setHeader ("WWW-Auth enticate", "Negotiat e"); | 166 | response .setHeader (AUTH_HEAD ER_NAME, A UTH_HEADER _VALUE_NEG OTIATE); | 165 | response .setHeader (AUTH_HEAD ER_NAME, A UTH_HEADER _VALUE_NEG OTIATE); | |||||
| 166 | response .sendError (HttpServl etResponse .SC_UNAUTH ORIZED); | 167 | response .sendError (HttpServl etResponse .SC_UNAUTH ORIZED); | 166 | response .sendError (HttpServl etResponse .SC_UNAUTH ORIZED); | |||||
| 167 | return f alse; | 168 | return f alse; | 167 | return f alse; | |||||
| 168 | } | 169 | } | 168 | } | |||||
| 169 | 170 | 169 | ||||||||
| 170 | au thorizatio nBC.setOff set(author izationBC. getOffset( ) + 10); | 171 | au thorizatio nBC.setOff set(author izationBC. getOffset( ) + 10); | 170 | au thorizatio nBC.setOff set(author izationBC. getOffset( ) + 10); | |||||
| 171 | 172 | 171 | ||||||||
| 172 | by te[] decod ed = Base6 4.decodeBa se64(autho rizationBC .getBuffer (), | 173 | by te[] decod ed = Base6 4.decodeBa se64(autho rizationBC .getBuffer (), | 172 | by te[] decod ed = Base6 4.decodeBa se64(autho rizationBC .getBuffer (), | |||||
| 173 | auth orizationB C.getOffse t(), | 174 | auth orizationB C.getOffse t(), | 173 | auth orizationB C.getOffse t(), | |||||
| 174 | auth orizationB C.getLengt h()); | 175 | auth orizationB C.getLengt h()); | 174 | auth orizationB C.getLengt h()); | |||||
| 175 | 176 | 175 | ||||||||
| 176 | if (getApply Java8u40Fi x()) { | 177 | if (getApply Java8u40Fi x()) { | 176 | if (getApply Java8u40Fi x()) { | |||||
| 177 | SpnegoTo kenFixer.f ix(decoded ); | 178 | SpnegoTo kenFixer.f ix(decoded ); | 177 | SpnegoTo kenFixer.f ix(decoded ); | |||||
| 178 | } | 179 | } | 178 | } | |||||
| 179 | 180 | 179 | ||||||||
| 180 | if (decoded. length == 0) { | 181 | if (decoded. length == 0) { | 180 | if (decoded. length == 0) { | |||||
| 181 | if (log. isDebugEna bled()) { | 182 | if (log. isDebugEna bled()) { | 181 | if (log. isDebugEna bled()) { | |||||
| 182 | log. debug(sm.g etString( | 183 | log. debug(sm.g etString( | 182 | log. debug(sm.g etString( | |||||
| 183 | "spneg oAuthentic ator.authH eaderNoTok en")); | 184 | "spneg oAuthentic ator.authH eaderNoTok en")); | 183 | "spneg oAuthentic ator.authH eaderNoTok en")); | |||||
| 184 | } | 185 | } | 184 | } | |||||
| 185 | response .setHeader ("WWW-Auth enticate", "Negotiat e"); | 186 | response .setHeader (AUTH_HEAD ER_NAME, A UTH_HEADER _VALUE_NEG OTIATE); | 185 | response .setHeader (AUTH_HEAD ER_NAME, A UTH_HEADER _VALUE_NEG OTIATE); | |||||
| 186 | response .sendError (HttpServl etResponse .SC_UNAUTH ORIZED); | 187 | response .sendError (HttpServl etResponse .SC_UNAUTH ORIZED); | 186 | response .sendError (HttpServl etResponse .SC_UNAUTH ORIZED); | |||||
| 187 | return f alse; | 188 | return f alse; | 187 | return f alse; | |||||
| 188 | } | 189 | } | 188 | } | |||||
| 189 | 190 | 189 | ||||||||
| 190 | Lo ginContext lc = null ; | 191 | Lo ginContext lc = null ; | 190 | Lo ginContext lc = null ; | |||||
| 191 | GS SContext g ssContext = null; | 192 | GS SContext g ssContext = null; | 191 | GS SContext g ssContext = null; | |||||
| 192 | by te[] outTo ken = null ; | 193 | by te[] outTo ken = null ; | 192 | by te[] outTo ken = null ; | |||||
| 193 | Pr incipal pr incipal = null; | 194 | Pr incipal pr incipal = null; | 193 | Pr incipal pr incipal = null; | |||||
| 194 | tr y { | 195 | tr y { | 194 | tr y { | |||||
| 195 | try { | 196 | try { | 195 | try { | |||||
| 196 | lc = new Login Context(ge tLoginConf igName()); | 197 | lc = new Login Context(ge tLoginConf igName()); | 196 | lc = new Login Context(ge tLoginConf igName()); | |||||
| 197 | lc.l ogin(); | 198 | lc.l ogin(); | 197 | lc.l ogin(); | |||||
| 198 | } catch (LoginExce ption e) { | 199 | } catch (LoginExce ption e) { | 198 | } catch (LoginExce ption e) { | |||||
| 199 | log. error(sm.g etString(" spnegoAuth enticator. serviceLog inFail"), | 200 | log. error(sm.g etString(" spnegoAuth enticator. serviceLog inFail"), | 199 | log. error(sm.g etString(" spnegoAuth enticator. serviceLog inFail"), | |||||
| 200 | e); | 201 | e); | 200 | e); | |||||
| 201 | resp onse.sendE rror( | 202 | resp onse.sendE rror( | 201 | resp onse.sendE rror( | |||||
| 202 | HttpSe rvletRespo nse.SC_INT ERNAL_SERV ER_ERROR); | 203 | HttpSe rvletRespo nse.SC_INT ERNAL_SERV ER_ERROR); | 202 | HttpSe rvletRespo nse.SC_INT ERNAL_SERV ER_ERROR); | |||||
| 203 | retu rn false; | 204 | retu rn false; | 203 | retu rn false; | |||||
| 204 | } | 205 | } | 204 | } | |||||
| 205 | 206 | 205 | ||||||||
| 206 | Subject subject = lc.getSubj ect(); | 207 | Subject subject = lc.getSubj ect(); | 206 | Subject subject = lc.getSubj ect(); | |||||
| 207 | 208 | 207 | ||||||||
| 208 | // Assum e the GSSC ontext is stateless | 209 | // Assum e the GSSC ontext is stateless | 208 | // Assum e the GSSC ontext is stateless | |||||
| 209 | // TODO: Confirm t his assump tion | 210 | // TODO: Confirm t his assump tion | 209 | // TODO: Confirm t his assump tion | |||||
| 210 | final GS SManager m anager = G SSManager. getInstanc e(); | 211 | final GS SManager m anager = G SSManager. getInstanc e(); | 210 | final GS SManager m anager = G SSManager. getInstanc e(); | |||||
| 211 | // IBM J DK only un derstands indefinite lifetime | 212 | // IBM J DK only un derstands indefinite lifetime | 211 | // IBM J DK only un derstands indefinite lifetime | |||||
| 212 | final in t credenti alLifetime ; | 213 | final in t credenti alLifetime ; | 212 | final in t credenti alLifetime ; | |||||
| 213 | if (JreV endor.IS_I BM_JVM) { | 214 | if (JreV endor.IS_I BM_JVM) { | 213 | if (JreV endor.IS_I BM_JVM) { | |||||
| 214 | cred entialLife time = GSS Credential .INDEFINIT E_LIFETIME ; | 215 | cred entialLife time = GSS Credential .INDEFINIT E_LIFETIME ; | 214 | cred entialLife time = GSS Credential .INDEFINIT E_LIFETIME ; | |||||
| 215 | } else { | 216 | } else { | 215 | } else { | |||||
| 216 | cred entialLife time = GSS Credential .DEFAULT_L IFETIME; | 217 | cred entialLife time = GSS Credential .DEFAULT_L IFETIME; | 216 | cred entialLife time = GSS Credential .DEFAULT_L IFETIME; | |||||
| 217 | } | 218 | } | 217 | } | |||||
| 218 | final Pr ivilegedEx ceptionAct ion<GSSCre dential> a ction = | 219 | final Pr ivilegedEx ceptionAct ion<GSSCre dential> a ction = | 218 | final Pr ivilegedEx ceptionAct ion<GSSCre dential> a ction = | |||||
| 219 | new Privileged ExceptionA ction<GSSC redential> () { | 220 | new Privileged ExceptionA ction<GSSC redential> () { | 219 | new Privileged ExceptionA ction<GSSC redential> () { | |||||
| 220 | @Override | 221 | @Override | 220 | @Override | |||||
| 221 | public GSS Credential run() thr ows GSSExc eption { | 222 | public GSS Credential run() thr ows GSSExc eption { | 221 | public GSS Credential run() thr ows GSSExc eption { | |||||
| 222 | return manager.c reateCrede ntial(null , | 223 | return manager.c reateCrede ntial(null , | 222 | return manager.c reateCrede ntial(null , | |||||
| 223 | credenti alLifetime , | 224 | credenti alLifetime , | 223 | credenti alLifetime , | |||||
| 224 | new Oid( "1.3.6.1.5 .5.2"), | 225 | new Oid( "1.3.6.1.5 .5.2"), | 224 | new Oid( "1.3.6.1.5 .5.2"), | |||||
| 225 | GSSCrede ntial.ACCE PT_ONLY); | 226 | GSSCrede ntial.ACCE PT_ONLY); | 225 | GSSCrede ntial.ACCE PT_ONLY); | |||||
| 226 | } | 227 | } | 226 | } | |||||
| 227 | }; | 228 | }; | 227 | }; | |||||
| 228 | gssConte xt = manag er.createC ontext(Sub ject.doAs( subject, a ction)); | 229 | gssConte xt = manag er.createC ontext(Sub ject.doAs( subject, a ction)); | 228 | gssConte xt = manag er.createC ontext(Sub ject.doAs( subject, a ction)); | |||||
| 229 | 230 | 229 | ||||||||
| 230 | outToken = Subject .doAs(lc.g etSubject( ), new Acc eptAction( gssContext , decoded) ); | 231 | outToken = Subject .doAs(lc.g etSubject( ), new Acc eptAction( gssContext , decoded) ); | 230 | outToken = Subject .doAs(lc.g etSubject( ), new Acc eptAction( gssContext , decoded) ); | |||||
| 231 | 232 | 231 | ||||||||
| 232 | if (outT oken == nu ll) { | 233 | if (outT oken == nu ll) { | 232 | if (outT oken == nu ll) { | |||||
| 233 | if ( log.isDebu gEnabled() ) { | 234 | if ( log.isDebu gEnabled() ) { | 233 | if ( log.isDebu gEnabled() ) { | |||||
| 234 | log.debug( sm.getStri ng( | 235 | log.debug( sm.getStri ng( | 234 | log.debug( sm.getStri ng( | |||||
| 235 | "s pnegoAuthe nticator.t icketValid ateFail")) ; | 236 | "s pnegoAuthe nticator.t icketValid ateFail")) ; | 235 | "s pnegoAuthe nticator.t icketValid ateFail")) ; | |||||
| 236 | } | 237 | } | 236 | } | |||||
| 237 | // S tart again | 238 | // S tart again | 237 | // S tart again | |||||
| 238 | resp onse.setHe ader("WWW- Authentica te", "Nego tiate"); | 239 | resp onse.setHe ader(AUTH_ HEADER_NAM E, AUTH_HE ADER_VALUE _NEGOTIATE ); | 238 | resp onse.setHe ader(AUTH_ HEADER_NAM E, AUTH_HE ADER_VALUE _NEGOTIATE ); | |||||
| 239 | resp onse.sendE rror(HttpS ervletResp onse.SC_UN AUTHORIZED ); | 240 | resp onse.sendE rror(HttpS ervletResp onse.SC_UN AUTHORIZED ); | 239 | resp onse.sendE rror(HttpS ervletResp onse.SC_UN AUTHORIZED ); | |||||
| 240 | retu rn false; | 241 | retu rn false; | 240 | retu rn false; | |||||
| 241 | } | 242 | } | 241 | } | |||||
| 242 | 243 | 242 | ||||||||
| 243 | principa l = Subjec t.doAs(sub ject, new Authentica teAction( | 244 | principa l = Subjec t.doAs(sub ject, new Authentica teAction( | 243 | principa l = Subjec t.doAs(sub ject, new Authentica teAction( | |||||
| 244 | context.ge tRealm(), gssContext , storeDel egatedCred ential)); | 245 | context.ge tRealm(), gssContext , storeDel egatedCred ential)); | 244 | context.ge tRealm(), gssContext , storeDel egatedCred ential)); | |||||
| 245 | 246 | 245 | ||||||||
| 246 | } catch (GSS Exception e) { | 247 | } catch (GSS Exception e) { | 246 | } catch (GSS Exception e) { | |||||
| 247 | if (log. isDebugEna bled()) { | 248 | if (log. isDebugEna bled()) { | 247 | if (log. isDebugEna bled()) { | |||||
| 248 | log. debug(sm.g etString(" spnegoAuth enticator. ticketVali dateFail") , e); | 249 | log. debug(sm.g etString(" spnegoAuth enticator. ticketVali dateFail") , e); | 248 | log. debug(sm.g etString(" spnegoAuth enticator. ticketVali dateFail") , e); | |||||
| 249 | } | 250 | } | 249 | } | |||||
| 250 | response .setHeader ("WWW-Auth enticate", "Negotiat e"); | 251 | response .setHeader (AUTH_HEAD ER_NAME, A UTH_HEADER _VALUE_NEG OTIATE); | 250 | response .setHeader (AUTH_HEAD ER_NAME, A UTH_HEADER _VALUE_NEG OTIATE); | |||||
| 251 | response .sendError (HttpServl etResponse .SC_UNAUTH ORIZED); | 252 | response .sendError (HttpServl etResponse .SC_UNAUTH ORIZED); | 251 | response .sendError (HttpServl etResponse .SC_UNAUTH ORIZED); | |||||
| 252 | return f alse; | 253 | return f alse; | 252 | return f alse; | |||||
| 253 | } catch (Pri vilegedAct ionExcepti on e) { | 254 | } catch (Pri vilegedAct ionExcepti on e) { | 253 | } catch (Pri vilegedAct ionExcepti on e) { | |||||
| 254 | Throwabl e cause = e.getCause (); | 255 | Throwabl e cause = e.getCause (); | 254 | Throwabl e cause = e.getCause (); | |||||
| 255 | if (caus e instance of GSSExce ption) { | 256 | if (caus e instance of GSSExce ption) { | 255 | if (caus e instance of GSSExce ption) { | |||||
| 256 | if ( log.isDebu gEnabled() ) { | 257 | if ( log.isDebu gEnabled() ) { | 256 | if ( log.isDebu gEnabled() ) { | |||||
| 257 | log.debug( sm.getStri ng("spnego Authentica tor.servic eLoginFail "), e); | 258 | log.debug( sm.getStri ng("spnego Authentica tor.servic eLoginFail "), e); | 257 | log.debug( sm.getStri ng("spnego Authentica tor.servic eLoginFail "), e); | |||||
| 258 | } | 259 | } | 258 | } | |||||
| 259 | } else { | 260 | } else { | 259 | } else { | |||||
| 260 | log. error(sm.g etString(" spnegoAuth enticator. serviceLog inFail"), e); | 261 | log. error(sm.g etString(" spnegoAuth enticator. serviceLog inFail"), e); | 260 | log. error(sm.g etString(" spnegoAuth enticator. serviceLog inFail"), e); | |||||
| 261 | } | 262 | } | 261 | } | |||||
| 262 | response .setHeader ("WWW-Auth enticate", "Negotiat e"); | 263 | response .setHeader (AUTH_HEAD ER_NAME, A UTH_HEADER _VALUE_NEG OTIATE); | 262 | response .setHeader (AUTH_HEAD ER_NAME, A UTH_HEADER _VALUE_NEG OTIATE); | |||||
| 263 | response .sendError (HttpServl etResponse .SC_UNAUTH ORIZED); | 264 | response .sendError (HttpServl etResponse .SC_UNAUTH ORIZED); | 263 | response .sendError (HttpServl etResponse .SC_UNAUTH ORIZED); | |||||
| 264 | return f alse; | 265 | return f alse; | 264 | return f alse; | |||||
| 265 | } finally { | 266 | } finally { | 265 | } finally { | |||||
| 266 | if (gssC ontext != null) { | 267 | if (gssC ontext != null) { | 266 | if (gssC ontext != null) { | |||||
| 267 | try { | 268 | try { | 267 | try { | |||||
| 268 | gssContext .dispose() ; | 269 | gssContext .dispose() ; | 268 | gssContext .dispose() ; | |||||
| 269 | } ca tch (GSSEx ception e) { | 270 | } ca tch (GSSEx ception e) { | 269 | } ca tch (GSSEx ception e) { | |||||
| 270 | // Ignore | 271 | // Ignore | 270 | // Ignore | |||||
| 271 | } | 272 | } | 271 | } | |||||
| 272 | } | 273 | } | 272 | } | |||||
| 273 | if (lc ! = null) { | 274 | if (lc ! = null) { | 273 | if (lc ! = null) { | |||||
| 274 | try { | 275 | try { | 274 | try { | |||||
| 275 | lc.logout( ); | 276 | lc.logout( ); | 275 | lc.logout( ); | |||||
| 276 | } ca tch (Login Exception e) { | 277 | } ca tch (Login Exception e) { | 276 | } ca tch (Login Exception e) { | |||||
| 277 | // Ignore | 278 | // Ignore | 277 | // Ignore | |||||
| 278 | } | 279 | } | 278 | } | |||||
| 279 | } | 280 | } | 279 | } | |||||
| 280 | } | 281 | } | 280 | } | |||||
| 281 | 282 | 281 | ||||||||
| 282 | // Send resp onse token on succes s and fail ure | 283 | // Send resp onse token on succes s and fail ure | 282 | // Send resp onse token on succes s and fail ure | |||||
| 283 | re sponse.set Header("WW W-Authenti cate", "Ne gotiate " | 284 | re sponse.set Header(AUT H_HEADER_N AME, AUTH_ HEADER_VAL UE_NEGOTIA TE + " " | 283 | re sponse.set Header(AUT H_HEADER_N AME, AUTH_ HEADER_VAL UE_NEGOTIA TE + " " | |||||
| 284 | + Ba se64.encod eBase64Str ing(outTok en)); | 285 | + Ba se64.encod eBase64Str ing(outTok en)); | 284 | + Ba se64.encod eBase64Str ing(outTok en)); | |||||
| 285 | 286 | 285 | ||||||||
| 286 | if (principa l != null) { | 287 | if (principa l != null) { | 286 | if (principa l != null) { | |||||
| 287 | register (request, response, principal, Constants .SPNEGO_ME THOD, | 288 | register (request, response, principal, Constants .SPNEGO_ME THOD, | 287 | register (request, response, principal, Constants .SPNEGO_ME THOD, | |||||
| 288 | principal. getName(), null); | 289 | principal. getName(), null); | 288 | principal. getName(), null); | |||||
| 289 | 290 | 289 | ||||||||
| 290 | Pattern p = noKeep AliveUserA gents; | 291 | Pattern p = noKeep AliveUserA gents; | 290 | Pattern p = noKeep AliveUserA gents; | |||||
| 291 | if (p != null) { | 292 | if (p != null) { | 291 | if (p != null) { | |||||
| 292 | Mess ageBytes u a = | 293 | Mess ageBytes u a = | 292 | Mess ageBytes u a = | |||||
| 293 | reques t.getCoyot eRequest() .getMimeHe aders().ge tValue( | 294 | reques t.getCoyot eRequest() .getMimeHe aders().ge tValue( | 293 | reques t.getCoyot eRequest() .getMimeHe aders().ge tValue( | |||||
| 294 | "user-ag ent"); | 295 | "user-ag ent"); | 294 | "user-ag ent"); | |||||
| 295 | if ( ua != null && p.matc her(ua.toS tring()).m atches()) { | 296 | if ( ua != null && p.matc her(ua.toS tring()).m atches()) { | 295 | if ( ua != null && p.matc her(ua.toS tring()).m atches()) { | |||||
| 296 | response.s etHeader(" Connection ", "close" ); | 297 | response.s etHeader(" Connection ", "close" ); | 296 | response.s etHeader(" Connection ", "close" ); | |||||
| 297 | } | 298 | } | 297 | } | |||||
| 298 | } | 299 | } | 298 | } | |||||
| 299 | return t rue; | 300 | return t rue; | 299 | return t rue; | |||||
| 300 | } | 301 | } | 300 | } | |||||
| 301 | 302 | 301 | ||||||||
| 302 | re sponse.sen dError(Htt pServletRe sponse.SC_ UNAUTHORIZ ED); | 303 | re sponse.sen dError(Htt pServletRe sponse.SC_ UNAUTHORIZ ED); | 302 | re sponse.sen dError(Htt pServletRe sponse.SC_ UNAUTHORIZ ED); | |||||
| 303 | re turn false ; | 304 | re turn false ; | 303 | re turn false ; | |||||
| 304 | } | 305 | } | 304 | } | |||||
| 305 | 306 | 305 | ||||||||
| 306 | 307 | 306 | ||||||||
| 307 | /** | 308 | /** | 307 | /** | |||||
| 308 | * Thi s class ge ts a gss c redential via a priv ileged act ion. | 309 | * Thi s class ge ts a gss c redential via a priv ileged act ion. | 308 | * Thi s class ge ts a gss c redential via a priv ileged act ion. | |||||
| 309 | */ | 310 | */ | 309 | */ | |||||
| 310 | p r i vate static cl ass Accept Action imp lements Pr ivilegedEx ceptionAct ion<byte[] > { | 311 | p ubl i c static cl ass Accept Action imp lements Pr ivilegedEx ceptionAct ion<byte[] > { | 310 | public static cl ass Accept Action imp lements Pr ivilegedEx ceptionAct ion<byte[] > { | |||||
| 311 | 312 | 311 | ||||||||
| 312 | GS SContext g ssContext; | 313 | GS SContext g ssContext; | 312 | GS SContext g ssContext; | |||||
| 313 | 314 | 313 | ||||||||
| 314 | by te[] decod ed; | 315 | by te[] decod ed; | 314 | by te[] decod ed; | |||||
| 315 | 316 | 315 | ||||||||
| 316 |
|
317 | public AcceptActi on(GSSCont ext contex t, byte[] decodedTok en) { | 316 | pu blic Accep tAction(GS SContext c ontext, by te[] decod edToken) { | |||||
| 317 | this.gss Context = context; | 318 | this.gss Context = context; | 317 | this.gss Context = context; | |||||
| 318 | this.dec oded = dec odedToken; | 319 | this.dec oded = dec odedToken; | 318 | this.dec oded = dec odedToken; | |||||
| 319 | } | 320 | } | 319 | } | |||||
| 320 | 321 | 320 | ||||||||
| 321 | @O verride | 322 | @O verride | 321 | @O verride | |||||
| 322 | pu blic byte[ ] run() th rows GSSEx ception { | 323 | pu blic byte[ ] run() th rows GSSEx ception { | 322 | pu blic byte[ ] run() th rows GSSEx ception { | |||||
| 323 | return g ssContext. acceptSecC ontext(dec oded, | 324 | return g ssContext. acceptSecC ontext(dec oded, | 323 | return g ssContext. acceptSecC ontext(dec oded, | |||||
| 324 | 0, decoded .length); | 325 | 0, decoded .length); | 324 | 0, decoded .length); | |||||
| 325 | } | 326 | } | 325 | } | |||||
| 326 | } | 327 | } | 326 | } | |||||
| 327 | 328 | 327 | ||||||||
| 328 | 329 | 328 | ||||||||
| 329 | p r i vate static cl ass Authen ticateActi on impleme nts Privil egedAction <Principal > { | 330 | p ubl i c static cl ass Authen ticateActi on impleme nts Privil egedAction <Principal > { | 329 | public static cl ass Authen ticateActi on impleme nts Privil egedAction <Principal > { | |||||
| 330 | 331 | 330 | ||||||||
| 331 | pr ivate fina l Realm re alm; | 332 | pr ivate fina l Realm re alm; | 331 | pr ivate fina l Realm re alm; | |||||
| 332 | pr ivate fina l GSSConte xt gssCont ext; | 333 | pr ivate fina l GSSConte xt gssCont ext; | 332 | pr ivate fina l GSSConte xt gssCont ext; | |||||
| 333 | pr ivate fina l boolean storeDeleg atedCreden tial; | 334 | pr ivate fina l boolean storeDeleg atedCreden tial; | 333 | pr ivate fina l boolean storeDeleg atedCreden tial; | |||||
| 334 | 335 | 334 | ||||||||
| 335 | pu blic Authe nticateAct ion(Realm realm, GSS Context gs sContext, | 336 | pu blic Authe nticateAct ion(Realm realm, GSS Context gs sContext, | 335 | pu blic Authe nticateAct ion(Realm realm, GSS Context gs sContext, | |||||
| 336 | bool ean storeD elegatedCr edential) { | 337 | bool ean storeD elegatedCr edential) { | 336 | bool ean storeD elegatedCr edential) { | |||||
| 337 | this.rea lm = realm ; | 338 | this.rea lm = realm ; | 337 | this.rea lm = realm ; | |||||
| 338 | this.gss Context = gssContext ; | 339 | this.gss Context = gssContext ; | 338 | this.gss Context = gssContext ; | |||||
| 339 | this.sto reDelegate dCredentia l = storeD elegatedCr edential; | 340 | this.sto reDelegate dCredentia l = storeD elegatedCr edential; | 339 | this.sto reDelegate dCredentia l = storeD elegatedCr edential; | |||||
| 340 | } | 341 | } | 340 | } | |||||
| 341 | 342 | 341 | ||||||||
| 342 | @O verride | 343 | @O verride | 342 | @O verride | |||||
| 343 | pu blic Princ ipal run() { | 344 | pu blic Princ ipal run() { | 343 | pu blic Princ ipal run() { | |||||
| 344 | return r ealm.authe nticate(gs sContext, storeDeleg atedCreden tial); | 345 | return r ealm.authe nticate(gs sContext, storeDeleg atedCreden tial); | 344 | return r ealm.authe nticate(gs sContext, storeDeleg atedCreden tial); | |||||
| 345 | } | 346 | } | 345 | } | |||||
| 346 | } | 347 | } | 346 | } | |||||
| 347 | 348 | 347 | ||||||||
| 348 | 349 | 348 | ||||||||
| 349 | /** | 350 | /** | 349 | /** | |||||
| 350 | * Thi s class im plements a hack arou nd an inco mpatibilit y between the | 351 | * Thi s class im plements a hack arou nd an inco mpatibilit y between the | 350 | * Thi s class im plements a hack arou nd an inco mpatibilit y between the | |||||
| 351 | * SPN EGO implem entation i n Windows and the SP NEGO imple mentation in Java 8 | 352 | * SPN EGO implem entation i n Windows and the SP NEGO imple mentation in Java 8 | 351 | * SPN EGO implem entation i n Windows and the SP NEGO imple mentation in Java 8 | |||||
| 352 | * upd ate 40 onw ards. It w as introdu ced by the change to fix this bug: | 353 | * upd ate 40 onw ards. It w as introdu ced by the change to fix this bug: | 352 | * upd ate 40 onw ards. It w as introdu ced by the change to fix this bug: | |||||
| 353 | * htt ps://bugs. openjdk.ja va.net/bro wse/JDK-80 48194 | 354 | * htt ps://bugs. openjdk.ja va.net/bro wse/JDK-80 48194 | 353 | * htt ps://bugs. openjdk.ja va.net/bro wse/JDK-80 48194 | |||||
| 354 | * (no te: the ch ange appli ed is not the one su ggested in the bug r eport) | 355 | * (no te: the ch ange appli ed is not the one su ggested in the bug r eport) | 354 | * (no te: the ch ange appli ed is not the one su ggested in the bug r eport) | |||||
| 355 | * <p> | 356 | * <p> | 355 | * <p> | |||||
| 356 | * It is not cle ar to me i f Windows, Java or T omcat is a t fault he re. I | 357 | * It is not cle ar to me i f Windows, Java or T omcat is a t fault he re. I | 356 | * It is not cle ar to me i f Windows, Java or T omcat is a t fault he re. I | |||||
| 357 | * thi nk it is J ava but I could be w rong. | 358 | * thi nk it is J ava but I could be w rong. | 357 | * thi nk it is J ava but I could be w rong. | |||||
| 358 | * <p> | 359 | * <p> | 358 | * <p> | |||||
| 359 | * Thi s hack wor ks by re-o rdering th e list of mechTypes in the Neg TokenInit | 360 | * Thi s hack wor ks by re-o rdering th e list of mechTypes in the Neg TokenInit | 359 | * Thi s hack wor ks by re-o rdering th e list of mechTypes in the Neg TokenInit | |||||
| 360 | * tok en. | 361 | * tok en. | 360 | * tok en. | |||||
| 361 | */ | 362 | */ | 361 | */ | |||||
| 362 | p r i vate static cl ass Spnego TokenFixer { | 363 | p ubl i c static cl ass Spnego TokenFixer { | 362 | public static cl ass Spnego TokenFixer { | |||||
| 363 | 364 | 363 | ||||||||
| 364 | pu blic stati c void fix (byte[] to ken) { | 365 | pu blic stati c void fix (byte[] to ken) { | 364 | pu blic stati c void fix (byte[] to ken) { | |||||
| 365 | SpnegoTo kenFixer f ixer = new SpnegoTok enFixer(to ken); | 366 | SpnegoTo kenFixer f ixer = new SpnegoTok enFixer(to ken); | 365 | SpnegoTo kenFixer f ixer = new SpnegoTok enFixer(to ken); | |||||
| 366 | fixer.fi x(); | 367 | fixer.fi x(); | 366 | fixer.fi x(); | |||||
| 367 | } | 368 | } | 367 | } | |||||
| 368 | 369 | 368 | ||||||||
| 369 | 370 | 369 | ||||||||
| 370 | pr ivate fina l byte[] t oken; | 371 | pr ivate fina l byte[] t oken; | 370 | pr ivate fina l byte[] t oken; | |||||
| 371 | pr ivate int pos = 0; | 372 | pr ivate int pos = 0; | 371 | pr ivate int pos = 0; | |||||
| 372 | 373 | 372 | ||||||||
| 373 | 374 | 373 | ||||||||
| 374 | pr ivate Spne goTokenFix er(byte[] token) { | 375 | pr ivate Spne goTokenFix er(byte[] token) { | 374 | pr ivate Spne goTokenFix er(byte[] token) { | |||||
| 375 | this.tok en = token ; | 376 | this.tok en = token ; | 375 | this.tok en = token ; | |||||
| 376 | } | 377 | } | 376 | } | |||||
| 377 | 378 | 377 | ||||||||
| 378 | 379 | 378 | ||||||||
| 379 | // Fixes the token in- place | 380 | // Fixes the token in- place | 379 | // Fixes the token in- place | |||||
| 380 | pr ivate void fix() { | 381 | pr ivate void fix() { | 380 | pr ivate void fix() { | |||||
| 381 | /* | 382 | /* | 381 | /* | |||||
| 382 | * Usefu l referenc es: | 383 | * Usefu l referenc es: | 382 | * Usefu l referenc es: | |||||
| 383 | * http: //tools.ie tf.org/htm l/rfc4121# page-5 | 384 | * http: //tools.ie tf.org/htm l/rfc4121# page-5 | 383 | * http: //tools.ie tf.org/htm l/rfc4121# page-5 | |||||
| 384 | * http: //tools.ie tf.org/htm l/rfc2743# page-81 | 385 | * http: //tools.ie tf.org/htm l/rfc2743# page-81 | 384 | * http: //tools.ie tf.org/htm l/rfc2743# page-81 | |||||
| 385 | * https ://msdn.mi crosoft.co m/en-us/li brary/ms99 5330.aspx | 386 | * https ://msdn.mi crosoft.co m/en-us/li brary/ms99 5330.aspx | 385 | * https ://msdn.mi crosoft.co m/en-us/li brary/ms99 5330.aspx | |||||
| 386 | */ | 387 | */ | 386 | */ | |||||
| 387 | 388 | 387 | ||||||||
| 388 | // Scan until we f ind the me ch types l ist. If we find anyt hing | 389 | // Scan until we f ind the me ch types l ist. If we find anyt hing | 388 | // Scan until we f ind the me ch types l ist. If we find anyt hing | |||||
| 389 | // unexp ected, abo rt the fix process. | 390 | // unexp ected, abo rt the fix process. | 389 | // unexp ected, abo rt the fix process. | |||||
| 390 | if (!tag (0x60)) re turn; | 391 | if (!tag (0x60)) re turn; | 390 | if (!tag (0x60)) re turn; | |||||
| 391 | if (!len gth()) ret urn; | 392 | if (!len gth()) ret urn; | 391 | if (!len gth()) ret urn; | |||||
| 392 | if (!oid ("1.3.6.1. 5.5.2")) r eturn; | 393 | if (!oid ("1.3.6.1. 5.5.2")) r eturn; | 392 | if (!oid ("1.3.6.1. 5.5.2")) r eturn; | |||||
| 393 | if (!tag (0xa0)) re turn; | 394 | if (!tag (0xa0)) re turn; | 393 | if (!tag (0xa0)) re turn; | |||||
| 394 | if (!len gth()) ret urn; | 395 | if (!len gth()) ret urn; | 394 | if (!len gth()) ret urn; | |||||
| 395 | if (!tag (0x30)) re turn; | 396 | if (!tag (0x30)) re turn; | 395 | if (!tag (0x30)) re turn; | |||||
| 396 | if (!len gth()) ret urn; | 397 | if (!len gth()) ret urn; | 396 | if (!len gth()) ret urn; | |||||
| 397 | if (!tag (0xa0)) re turn; | 398 | if (!tag (0xa0)) re turn; | 397 | if (!tag (0xa0)) re turn; | |||||
| 398 | lengthAs Int(); | 399 | lengthAs Int(); | 398 | lengthAs Int(); | |||||
| 399 | if (!tag (0x30)) re turn; | 400 | if (!tag (0x30)) re turn; | 399 | if (!tag (0x30)) re turn; | |||||
| 400 | // Now a t the star t of the m echType li st. | 401 | // Now a t the star t of the m echType li st. | 400 | // Now a t the star t of the m echType li st. | |||||
| 401 | // Read the mechTy pes into a n ordered set | 402 | // Read the mechTy pes into a n ordered set | 401 | // Read the mechTy pes into a n ordered set | |||||
| 402 | int mech TypesLen = lengthAsI nt(); | 403 | int mech TypesLen = lengthAsI nt(); | 402 | int mech TypesLen = lengthAsI nt(); | |||||
| 403 | int mech TypesStart = pos; | 404 | int mech TypesStart = pos; | 403 | int mech TypesStart = pos; | |||||
| 404 | LinkedHa shMap<Stri ng, int[]> mechTypeE ntries = n ew LinkedH ashMap<>() ; | 405 | LinkedHa shMap<Stri ng, int[]> mechTypeE ntries = n ew LinkedH ashMap<>() ; | 404 | LinkedHa shMap<Stri ng, int[]> mechTypeE ntries = n ew LinkedH ashMap<>() ; | |||||
| 405 | while (p os < mechT ypesStart + mechType sLen) { | 406 | while (p os < mechT ypesStart + mechType sLen) { | 405 | while (p os < mechT ypesStart + mechType sLen) { | |||||
| 406 | int[ ] value = new int[2] ; | 407 | int[ ] value = new int[2] ; | 406 | int[ ] value = new int[2] ; | |||||
| 407 | valu e[0] = pos ; | 408 | valu e[0] = pos ; | 407 | valu e[0] = pos ; | |||||
| 408 | Stri ng key = o idAsString (); | 409 | Stri ng key = o idAsString (); | 408 | Stri ng key = o idAsString (); | |||||
| 409 | valu e[1] = pos - value[0 ]; | 410 | valu e[1] = pos - value[0 ]; | 409 | valu e[1] = pos - value[0 ]; | |||||
| 410 | mech TypeEntrie s.put(key, value); | 411 | mech TypeEntrie s.put(key, value); | 410 | mech TypeEntrie s.put(key, value); | |||||
| 411 | } | 412 | } | 411 | } | |||||
| 412 | // Now c onstruct t he re-orde red mechTy pe list | 413 | // Now c onstruct t he re-orde red mechTy pe list | 412 | // Now c onstruct t he re-orde red mechTy pe list | |||||
| 413 | byte[] r eplacement = new byt e[mechType sLen]; | 414 | byte[] r eplacement = new byt e[mechType sLen]; | 413 | byte[] r eplacement = new byt e[mechType sLen]; | |||||
| 414 | int repl acementPos = 0; | 415 | int repl acementPos = 0; | 414 | int repl acementPos = 0; | |||||
| 415 | 416 | 415 | ||||||||
| 416 | int[] fi rst = mech TypeEntrie s.remove(" 1.2.840.11 3554.1.2.2 "); | 417 | int[] fi rst = mech TypeEntrie s.remove(" 1.2.840.11 3554.1.2.2 "); | 416 | int[] fi rst = mech TypeEntrie s.remove(" 1.2.840.11 3554.1.2.2 "); | |||||
| 417 | if (firs t != null) { | 418 | if (firs t != null) { | 417 | if (firs t != null) { | |||||
| 418 | Syst em.arrayco py(token, first[0], replacemen t, replace mentPos, f irst[1]); | 419 | Syst em.arrayco py(token, first[0], replacemen t, replace mentPos, f irst[1]); | 418 | Syst em.arrayco py(token, first[0], replacemen t, replace mentPos, f irst[1]); | |||||
| 419 | repl acementPos += first[ 1]; | 420 | repl acementPos += first[ 1]; | 419 | repl acementPos += first[ 1]; | |||||
| 420 | } | 421 | } | 420 | } | |||||
| 421 | for (int [] markers : mechTyp eEntries.v alues()) { | 422 | for (int [] markers : mechTyp eEntries.v alues()) { | 421 | for (int [] markers : mechTyp eEntries.v alues()) { | |||||
| 422 | Syst em.arrayco py(token, markers[0] , replacem ent, repla cementPos, markers[1 ]); | 423 | Syst em.arrayco py(token, markers[0] , replacem ent, repla cementPos, markers[1 ]); | 422 | Syst em.arrayco py(token, markers[0] , replacem ent, repla cementPos, markers[1 ]); | |||||
| 423 | repl acementPos += marker s[1]; | 424 | repl acementPos += marker s[1]; | 423 | repl acementPos += marker s[1]; | |||||
| 424 | } | 425 | } | 424 | } | |||||
| 425 | 426 | 425 | ||||||||
| 426 | // Final ly, replac e the orig inal mechT ype list w ith the re -ordered | 427 | // Final ly, replac e the orig inal mechT ype list w ith the re -ordered | 426 | // Final ly, replac e the orig inal mechT ype list w ith the re -ordered | |||||
| 427 | // one. | 428 | // one. | 427 | // one. | |||||
| 428 | System.a rraycopy(r eplacement , 0, token , mechType sStart, me chTypesLen ); | 429 | System.a rraycopy(r eplacement , 0, token , mechType sStart, me chTypesLen ); | 428 | System.a rraycopy(r eplacement , 0, token , mechType sStart, me chTypesLen ); | |||||
| 429 | } | 430 | } | 429 | } | |||||
| 430 | 431 | 430 | ||||||||
| 431 | 432 | 431 | ||||||||
| 432 | pr ivate bool ean tag(in t expected ) { | 433 | pr ivate bool ean tag(in t expected ) { | 432 | pr ivate bool ean tag(in t expected ) { | |||||
| 433 | return ( token[pos+ +] & 0xFF) == expect ed; | 434 | return ( token[pos+ +] & 0xFF) == expect ed; | 433 | return ( token[pos+ +] & 0xFF) == expect ed; | |||||
| 434 | } | 435 | } | 434 | } | |||||
| 435 | 436 | 435 | ||||||||
| 436 | 437 | 436 | ||||||||
| 437 | pr ivate bool ean length () { | 438 | pr ivate bool ean length () { | 437 | pr ivate bool ean length () { | |||||
| 438 | // No ne ed to reta in the len gth - just need to c onsume it and make | 439 | // No ne ed to reta in the len gth - just need to c onsume it and make | 438 | // No ne ed to reta in the len gth - just need to c onsume it and make | |||||
| 439 | // sure it is vali d. | 440 | // sure it is vali d. | 439 | // sure it is vali d. | |||||
| 440 | int len = lengthAs Int(); | 441 | int len = lengthAs Int(); | 440 | int len = lengthAs Int(); | |||||
| 441 | return p os + len = = token.le ngth; | 442 | return p os + len = = token.le ngth; | 441 | return p os + len = = token.le ngth; | |||||
| 442 | } | 443 | } | 442 | } | |||||
| 443 | 444 | 443 | ||||||||
| 444 | 445 | 444 | ||||||||
| 445 | pr ivate int lengthAsIn t() { | 446 | pr ivate int lengthAsIn t() { | 445 | pr ivate int lengthAsIn t() { | |||||
| 446 | int len = token[po s++] & 0xF F; | 447 | int len = token[po s++] & 0xF F; | 446 | int len = token[po s++] & 0xF F; | |||||
| 447 | if (len > 127) { | 448 | if (len > 127) { | 447 | if (len > 127) { | |||||
| 448 | int bytes = le n - 128; | 449 | int bytes = le n - 128; | 448 | int bytes = le n - 128; | |||||
| 449 | len = 0; | 450 | len = 0; | 449 | len = 0; | |||||
| 450 | for (int i = 0 ; i < byte s; i++) { | 451 | for (int i = 0 ; i < byte s; i++) { | 450 | for (int i = 0 ; i < byte s; i++) { | |||||
| 451 | len = len << 8; | 452 | len = len << 8; | 451 | len = len << 8; | |||||
| 452 | len = len + (token[p os++] & 0x ff); | 453 | len = len + (token[p os++] & 0x ff); | 452 | len = len + (token[p os++] & 0x ff); | |||||
| 453 | } | 454 | } | 453 | } | |||||
| 454 | } | 455 | } | 454 | } | |||||
| 455 | return l en; | 456 | return l en; | 455 | return l en; | |||||
| 456 | } | 457 | } | 456 | } | |||||
| 457 | 458 | 457 | ||||||||
| 458 | 459 | 458 | ||||||||
| 459 | pr ivate bool ean oid(St ring expec ted) { | 460 | pr ivate bool ean oid(St ring expec ted) { | 459 | pr ivate bool ean oid(St ring expec ted) { | |||||
| 460 | return e xpected.eq uals(oidAs String()); | 461 | return e xpected.eq uals(oidAs String()); | 460 | return e xpected.eq uals(oidAs String()); | |||||
| 461 | } | 462 | } | 461 | } | |||||
| 462 | 463 | 462 | ||||||||
| 463 | 464 | 463 | ||||||||
| 464 | pr ivate Stri ng oidAsSt ring() { | 465 | pr ivate Stri ng oidAsSt ring() { | 464 | pr ivate Stri ng oidAsSt ring() { | |||||
| 465 | if (!tag (0x06)) re turn null; | 466 | if (!tag (0x06)) re turn null; | 465 | if (!tag (0x06)) re turn null; | |||||
| 466 | StringBu ilder resu lt = new S tringBuild er(); | 467 | StringBu ilder resu lt = new S tringBuild er(); | 466 | StringBu ilder resu lt = new S tringBuild er(); | |||||
| 467 | int len = lengthAs Int(); | 468 | int len = lengthAs Int(); | 467 | int len = lengthAs Int(); | |||||
| 468 | // First byte is s pecial cas e | 469 | // First byte is s pecial cas e | 468 | // First byte is s pecial cas e | |||||
| 469 | int v = token[pos+ +] & 0xFF; | 470 | int v = token[pos+ +] & 0xFF; | 469 | int v = token[pos+ +] & 0xFF; | |||||
| 470 | int c2 = v % 40; | 471 | int c2 = v % 40; | 470 | int c2 = v % 40; | |||||
| 471 | int c1 = (v - c2) / 40; | 472 | int c1 = (v - c2) / 40; | 471 | int c1 = (v - c2) / 40; | |||||
| 472 | result.a ppend(c1); | 473 | result.a ppend(c1); | 472 | result.a ppend(c1); | |||||
| 473 | result.a ppend('.') ; | 474 | result.a ppend('.') ; | 473 | result.a ppend('.') ; | |||||
| 474 | result.a ppend(c2); | 475 | result.a ppend(c2); | 474 | result.a ppend(c2); | |||||
| 475 | int c = 0; | 476 | int c = 0; | 475 | int c = 0; | |||||
| 476 | boolean write = fa lse; | 477 | boolean write = fa lse; | 476 | boolean write = fa lse; | |||||
| 477 | for (int i = 1; i < len; i++ ) { | 478 | for (int i = 1; i < len; i++ ) { | 477 | for (int i = 1; i < len; i++ ) { | |||||
| 478 | int b = token[ pos++] & 0 xFF; | 479 | int b = token[ pos++] & 0 xFF; | 478 | int b = token[ pos++] & 0 xFF; | |||||
| 479 | if ( b > 127) { | 480 | if ( b > 127) { | 479 | if ( b > 127) { | |||||
| 480 | b -= 128; | 481 | b -= 128; | 480 | b -= 128; | |||||
| 481 | } el se { | 482 | } el se { | 481 | } el se { | |||||
| 482 | write = tr ue; | 483 | write = tr ue; | 482 | write = tr ue; | |||||
| 483 | } | 484 | } | 483 | } | |||||
| 484 | c = c << 7; | 485 | c = c << 7; | 484 | c = c << 7; | |||||
| 485 | c += b; | 486 | c += b; | 485 | c += b; | |||||
| 486 | if ( write) { | 487 | if ( write) { | 486 | if ( write) { | |||||
| 487 | result.app end('.'); | 488 | result.app end('.'); | 487 | result.app end('.'); | |||||
| 488 | result.app end(c); | 489 | result.app end(c); | 488 | result.app end(c); | |||||
| 489 | c = 0; | 490 | c = 0; | 489 | c = 0; | |||||
| 490 | write = fa lse; | 491 | write = fa lse; | 490 | write = fa lse; | |||||
| 491 | } | 492 | } | 491 | } | |||||
| 492 | } | 493 | } | 492 | } | |||||
| 493 | return r esult.toSt ring(); | 494 | return r esult.toSt ring(); | 493 | return r esult.toSt ring(); | |||||
| 494 | } | 495 | } | 494 | } | |||||
| 495 | } | 496 | } | 495 | } | |||||
| 496 | } | 497 | } | 496 | } |
Araxis Merge (but not the data content of this report) is Copyright © 1993–2017 Araxis Ltd (www.araxis.com). All rights reserved.