diff options
Diffstat (limited to 'id/server/idserverlib/src/test')
4 files changed, 0 insertions, 543 deletions
diff --git a/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/CertTest.java b/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/CertTest.java deleted file mode 100644 index 6cf1e8280..000000000 --- a/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/CertTest.java +++ /dev/null @@ -1,131 +0,0 @@ -/******************************************************************************* - * Copyright 2014 Federal Chancellery Austria - * MOA-ID has been developed in a cooperation between BRZ, the Federal - * Chancellery Austria - ICT staff unit, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://www.osor.eu/eupl/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -package test.at.gv.egovernment.moa.id.auth.oauth; - -import iaik.security.ecc.provider.ECCProvider; - -import java.security.KeyStore; -import java.security.PrivateKey; -import java.security.cert.X509Certificate; - -import net.oauth.jsontoken.crypto.Signer; -import net.oauth.jsontoken.crypto.Verifier; - -import org.opensaml.xml.security.x509.BasicX509Credential; -import org.testng.Assert; -import org.testng.annotations.Test; - -import at.gv.egovernment.moa.id.protocols.oauth20.json.OAuth20SHA256Signer; -import at.gv.egovernment.moa.id.protocols.oauth20.json.OAuth20SHA256Verifier; -import at.gv.egovernment.moa.util.KeyStoreUtils; - -public class CertTest { - - /** KeyStore Path */ - private String rsaKeyStorePath = "file:/D:/dev/work/exthex/workspace/OAuthTesting/resources/keys/test_keystore.jks"; - - private String ecdsaKeyStorePath = "file:/D:/dev/work/exthex/workspace/OAuthTesting/resources/keys/ECDSA_keystore.jks"; - - /** KeyStore Password */ - private String keyStorePassword = "test12"; - - /** Specific Key Name as Credential */ - private String keyName = "1"; - - /** Key password */ - private String keyPassword = "test12"; - - private BasicX509Credential getCredentials(String keyStorePath) { - Assert.assertNotNull(keyStorePath); - - // KeyStorePassword optional - // if (StringUtils.isEmpty(this.keyStorePassword)) - // throw new SAMLException("No keyStorePassword specified"); - - Assert.assertNotNull(this.keyName); - - // KeyStorePassword optional - // if (StringUtils.isEmpty(this.keyPassword)) - // throw new SAMLException("No keyPassword specified"); - - KeyStore ks = null; - try { - ks = KeyStoreUtils.loadKeyStore(keyStorePath, this.keyStorePassword); - - } - catch (Exception e) { - e.printStackTrace(); - } - - // return new KeyStoreX509CredentialAdapter(ks, keyName, keyPwd.toCharArray()); - BasicX509Credential credential = null; - try { - X509Certificate certificate = (X509Certificate) ks.getCertificate(this.keyName); - - PrivateKey privateKey = (PrivateKey) ks.getKey(this.keyName, this.keyPassword.toCharArray()); - - // System.out.println("KS Provider:" + privateKey.getClass()); - credential = new BasicX509Credential(); - credential.setEntityCertificate(certificate); - credential.setPrivateKey(privateKey); - - System.out.println("Private Key: " + privateKey); - - } - catch (Exception e) { - e.printStackTrace(); - - } - - return credential; - } - - private void signAndVerify(BasicX509Credential credential) throws Exception { - String data = "someData"; - - Signer signer = new OAuth20SHA256Signer("signer1", keyName, credential.getPrivateKey()); - - byte[] signedData = signer.sign(data.getBytes()); - - Verifier verifier = new OAuth20SHA256Verifier(credential.getPublicKey()); - verifier.verifySignature(data.getBytes(), signedData); - } - - @Test - // (enabled = false) - public void testRSA() throws Exception { - BasicX509Credential credential = this.getCredentials(this.rsaKeyStorePath); - - // System.out.println(credential); - this.signAndVerify(credential); - } - - @Test - public void testECDSA() throws Exception { - ECCProvider.addAsProvider(); - - // Security.addProvider(new ECCProvider()); - BasicX509Credential credential = this.getCredentials(this.ecdsaKeyStorePath); - this.signAndVerify(credential); - } -} diff --git a/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/OAuth20ErrorsTests.java b/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/OAuth20ErrorsTests.java deleted file mode 100644 index abfca4f36..000000000 --- a/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/OAuth20ErrorsTests.java +++ /dev/null @@ -1,184 +0,0 @@ -package test.at.gv.egovernment.moa.id.auth.oauth; - -import java.io.IOException; - -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.methods.GetMethod; -import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.Assert; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20Constants; -import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20Util; - -import com.google.api.client.extensions.java6.auth.oauth2.VerificationCodeReceiver; -import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver; - -public class OAuth20ErrorsTests { - - final static Logger log = LoggerFactory.getLogger(OAuth20ErrorsTests.class); - - private static VerificationCodeReceiver receiver; - - // base uri - private static String OAUTH2_BASE_URI = "https://localhost/moa-id-auth/"; - // auth action - private static String OAUTH2_AUTH_URI = OAUTH2_BASE_URI + "oauth2/auth"; - // token action - private static String OAUTH2_TOKEN_URI = OAUTH2_BASE_URI + "oauth2/token"; - - // client id - private static String CLIENT_ID = "http://test"; - // client secret - private static String CLIENT_SECRET = "d435cf0a-3933-48f7-b142-339710c8f070"; - // OAuth 2.0 scopes - //private static List<String> SCOPES = Arrays.asList("testScope1", "testScope2"); - // state - private static String STATE = "testState"; - // code - private static String CODE = "code"; - // redirect uri - private static String REDIRECT_URI = "http://localhost:59542/Callback"; - - @BeforeMethod - public void beforeTest() throws Exception { - receiver = new LocalServerReceiver.Builder().setPort(59542).build(); - // REDIRECT_URI = receiver.getRedirectUri(); - // start - receiver.getRedirectUri(); - } - - @AfterMethod - public void afterTest() { - try { - receiver.stop(); - } - catch (IOException e) { - } - } - - private void checkParam(final String paramString, final String paramName) { - String[] help = paramString.split("="); - Assert.assertEquals(help[0], paramName); - Assert.assertTrue(StringUtils.isNotEmpty(help[1])); - } - - private void checkParams(final String queryString) { - // System.out.println("QueryString: " + queryString); - - System.out.println("Result url: " + queryString); - - String[] params = queryString.split("&"); - - this.checkParam(params[0], OAuth20Constants.PARAM_ERROR); - this.checkParam(params[1], OAuth20Constants.PARAM_ERROR_DESCRIPTION); - // this.checkParam(params[2], OAuth20Constants.PARAM_ERROR_URI); - // this.checkParam(params[3], OAuth20Constants.PARAM_STATE); - this.checkParam(params[2], OAuth20Constants.PARAM_STATE); - } - - class OAuthRequestParameters { - String redirectUri; - String clientId; - String responseType; - String scope; - String state; - String error; - - public OAuthRequestParameters(String redirectUri, String clientId, String responseType, String scope, String state, - String error) { - this.redirectUri = redirectUri; - this.clientId = clientId; - this.responseType = responseType; - this.scope = scope; - this.state = state; - this.error = error; - } - } - - @DataProvider(name = "parameter") - public Object[][] parameterProvider() { - // parameter is missing - // OAuthRequestParameters p0 = new OAuthRequestParameters(null, OA_URL, CLIENT_ID, CODE, - // "testScope1", null, - // "User authorization failed (invalid_request)"); - // OAuthRequestParameters p1 = new OAuthRequestParameters(REDIRECT_URI, CLIENT_ID, CODE, - // "testScope1", STATE, - // "User authorization failed (invalid_request)"); - OAuthRequestParameters p2 = new OAuthRequestParameters(REDIRECT_URI, null, CODE, "testScope1", STATE, - "User authorization failed (invalid_request)"); - OAuthRequestParameters p3 = new OAuthRequestParameters(REDIRECT_URI, CLIENT_ID, null, "testScope1", STATE, - "User authorization failed (invalid_request)"); - OAuthRequestParameters p4 = new OAuthRequestParameters(REDIRECT_URI, CLIENT_ID, CODE, null, STATE, null); - OAuthRequestParameters p5 = new OAuthRequestParameters(REDIRECT_URI, CLIENT_ID, CODE, "testScope1", null, - "User authorization failed (invalid_request)"); - - // wrong response type - OAuthRequestParameters p6 = new OAuthRequestParameters(REDIRECT_URI, CLIENT_ID, "WRONG_CODE", "testScope1", STATE, - "User authorization failed (unsupported_response_type)"); - // wrong client id - OAuthRequestParameters p7 = new OAuthRequestParameters(REDIRECT_URI, "wrongClient", CODE, "testScope1", STATE, - "User authorization failed (invalid_request)"); - // wrong redirect uri - // OAuthRequestParameters p9 = new OAuthRequestParameters("wrongURI", OA_URL, "wrongClient", - // CODE, "testScope1", STATE, - // "User authorization failed (access_denied)"); - - return new Object[][] { { p2 }, { p3 }, { p4 }, { p5 }, { p6 }, { p7 } }; - } - - @Test(dataProvider = "parameter", enabled = false) - public void testMissingParams(OAuthRequestParameters p) throws Exception { - StringBuilder url = new StringBuilder(); - url.append(OAUTH2_AUTH_URI); - - if (StringUtils.isNotEmpty(p.redirectUri)) OAuth20Util.addParameterToURL(url, "redirect_uri", p.redirectUri); - if (StringUtils.isNotEmpty(p.clientId)) OAuth20Util.addParameterToURL(url, "client_id", p.clientId); - if (StringUtils.isNotEmpty(p.responseType)) OAuth20Util.addParameterToURL(url, "response_type", p.responseType); - if (StringUtils.isNotEmpty(p.scope)) OAuth20Util.addParameterToURL(url, "scope", p.scope); - if (StringUtils.isNotEmpty(p.state)) OAuth20Util.addParameterToURL(url, "state", p.state); - - String finalUrl = url.toString(); - System.out.println("Calling: " + finalUrl); - - HttpClient client = new HttpClient(); - GetMethod get = new GetMethod(finalUrl); - int res = client.executeMethod(get); - Assert.assertEquals(res, HttpServletResponse.SC_OK); - - // assert - - if (p.error == null) { - Assert.assertFalse(get.getQueryString().contains("error")); - // receiver.waitForCode(); - } else { - // check if all error params are returned - this.checkParams(get.getQueryString()); - try { - receiver.waitForCode(); - Assert.assertTrue(false); - } - catch (Exception e) { - Assert.assertEquals(e.getMessage(), p.error); - } - } - } - - @Test(enabled = false) - public void testTokenErrorResponse() throws Exception { - HttpClient client = new HttpClient(); - GetMethod get = new GetMethod(OAUTH2_TOKEN_URI + "&client_id=" + CLIENT_ID + "&client_secret=" + CLIENT_SECRET - + "&code=test&grant_type=authorization_code"); - int res = client.executeMethod(get); - - System.out.println(res); - System.out.println(get.getResponseBodyAsString()); - } -} diff --git a/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/OAuth20GoogleClientTestCase.java b/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/OAuth20GoogleClientTestCase.java deleted file mode 100644 index 53c7ad496..000000000 --- a/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/OAuth20GoogleClientTestCase.java +++ /dev/null @@ -1,158 +0,0 @@ -/******************************************************************************* - * Copyright 2014 Federal Chancellery Austria - * MOA-ID has been developed in a cooperation between BRZ, the Federal - * Chancellery Austria - ICT staff unit, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://www.osor.eu/eupl/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -package test.at.gv.egovernment.moa.id.auth.oauth; - -import java.awt.Desktop; -import java.awt.Desktop.Action; -import java.io.IOException; -import java.math.BigInteger; -import java.net.URI; -import java.security.SecureRandom; -import java.util.Arrays; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.Assert; -import org.testng.annotations.Test; - -import com.google.api.client.auth.oauth2.AuthorizationCodeFlow; -import com.google.api.client.auth.oauth2.AuthorizationCodeRequestUrl; -import com.google.api.client.auth.oauth2.BearerToken; -import com.google.api.client.auth.oauth2.ClientParametersAuthentication; -import com.google.api.client.auth.oauth2.TokenResponse; -import com.google.api.client.auth.openidconnect.IdToken; -import com.google.api.client.extensions.java6.auth.oauth2.VerificationCodeReceiver; -import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver; -import com.google.api.client.http.GenericUrl; -import com.google.api.client.http.HttpExecuteInterceptor; -import com.google.api.client.http.HttpTransport; -import com.google.api.client.http.javanet.NetHttpTransport; -import com.google.api.client.json.JsonFactory; -import com.google.api.client.json.jackson2.JacksonFactory; - -public class OAuth20GoogleClientTestCase { - - final static Logger log = LoggerFactory.getLogger(OAuth20GoogleClientTestCase.class); - - // private static FileDataStoreFactory DATA_STORE_FACTORY; - - // Global instance of the HTTP transport. - private static HttpTransport HTTP_TRANSPORT = new NetHttpTransport(); - // Global instance of the JSON factory. - private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance(); - - private static String ISS = "https://localhost/moa-id-auth/"; - - // base uri - //private static String OAUTH2_BASE_URI = ISS + "dispatcher"; - // auth action - //private static String OAUTH2_AUTH_URI = OAUTH2_BASE_URI + "?mod=id_oauth20&action=AUTH"; - private static String OAUTH2_AUTH_URI = ISS + "oauth2/auth"; - - // token action - //private static String OAUTH2_TOKEN_URI = OAUTH2_BASE_URI + "?mod=id_oauth20&action=TOKEN"; - private static String OAUTH2_TOKEN_URI = ISS + "oauth2/token"; - - // client id - private static String CLIENT_ID = "http://test"; - // client secret - private static String CLIENT_SECRET = "d435cf0a-3933-48f7-b142-339710c8f070"; - // OAuth 2.0 scopes - private static final List<String> SCOPES = Arrays.asList("profile", "eID", "eID_gov", "mandate"); - - // open browser for bku login - private void openURL(String url) { - Assert.assertNotNull(url); - log.info("Please open the following URL in your browser:"); - log.info(url); - if (Desktop.isDesktopSupported()) { - Desktop desktop = Desktop.getDesktop(); - if (desktop.isSupported(Action.BROWSE)) { - try { - desktop.browse(URI.create(url)); - return; - } - catch (IOException e) { - // handled below - } - } - } - - } - - private TokenResponse authorize() throws Exception { - // set up a receiver for the callback - VerificationCodeReceiver receiver = new LocalServerReceiver.Builder().setPort(59542).build(); - - // create AuthorizationCodeFlow - GenericUrl token_uri = new GenericUrl(OAUTH2_TOKEN_URI); - HttpExecuteInterceptor credentials = new ClientParametersAuthentication(CLIENT_ID, CLIENT_SECRET); - AuthorizationCodeFlow flow = new AuthorizationCodeFlow.Builder(BearerToken.queryParameterAccessMethod(), HTTP_TRANSPORT, - JSON_FACTORY, token_uri, credentials, CLIENT_ID, OAUTH2_AUTH_URI).setScopes(SCOPES).build(); - // .setDataStoreFactory(DATA_STORE_FACTORY) - - // create AuthorizationCodeRequestUrl - try { - String redirectUri = receiver.getRedirectUri(); - String state = new BigInteger(130, new SecureRandom()).toString(32); - AuthorizationCodeRequestUrl authorizationUrl = flow.newAuthorizationUrl().setRedirectUri(redirectUri).setState(state); - - // open in browser - this.openURL(authorizationUrl.build()); - - // receive authorization code and exchange it for an access token - String code = receiver.waitForCode(); - System.out.println(code); - TokenResponse response = flow.newTokenRequest(code).setRedirectUri(redirectUri).execute(); - return response; - } - finally { - // if anything fails, stop the receiver - receiver.stop(); - } - - } - - // eyJhbGciOiJSUzI1NiIsImtpZCI6IjEifQ.eyJpc3MiOiJodHRwczovL2xvY2FsaG9zdC9tb2EtaWQtYXV0aC8iLCJleHAiOi02MzE5MDMsInN1YiI6IncveThQY2pNTHBFTGZmUHRTSDNtbmd6M24rRVx1MDAzZCIsImJpcnRoZGF0ZSI6IjE5ODUtMDItMDEiLCJmYW1pbHlfbmFtZSI6IkhpZXNzIiwiZ2l2ZW5fbmFtZSI6Ik1pY2hhZWwiLCJpYXQiOi02MzIyMDN9.Z_jveITHlTtktPOOV3n_sMbg50YQ4YcOEcSUs_RJ-4FGedj1sVxk9gmlUQcBPfQaBrPgC6RoiPLTy8CKu2PBClEyv9c9HdzIGqBjWzaTSNASx_QL5bfG4EQ8VZmSEI9d0whzlaBgkUFNfhx-Q2ZVh-g8SJ-0JO0zFR18OSRNTxPTJ4PPl0APqn2H-98sU331_zQKiZxNOvl_6OG26VoIYwEuW5m_N5tsf4lLAlqYcdHR3iNTeu8AkAOvlEwv7Z3BeeOiP4u-OWuc6VusWBPxaI2NwmDIoorpyIxY-wEFb4CWICuyk61Wlq1SCNdl-f-ODwJBK3rlj0IMlYbAjKSB0g - private void verifyIdToken(TokenResponse response) throws Exception { - String id_token = (String) response.getUnknownKeys().get("id_token"); - log.info("going to parse id token: {}", id_token); - - IdToken idToken = IdToken.parse(JSON_FACTORY, id_token); - Assert.assertTrue(idToken.verifyIssuer(ISS)); - - log.info(idToken.getPayload().toPrettyString()); - log.info(idToken.getHeader().toPrettyString()); - - } - - @Test(enabled = false) - public void testServerFlow() throws Exception { - TokenResponse response = this.authorize(); - log.info(response.toPrettyString()); - - this.verifyIdToken(response); - } - -} diff --git a/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/OAuth20UtilTest.java b/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/OAuth20UtilTest.java deleted file mode 100644 index 8e18adc08..000000000 --- a/id/server/idserverlib/src/test/java/test/at/gv/egovernment/moa/id/auth/oauth/OAuth20UtilTest.java +++ /dev/null @@ -1,70 +0,0 @@ -/******************************************************************************* - * Copyright 2014 Federal Chancellery Austria - * MOA-ID has been developed in a cooperation between BRZ, the Federal - * Chancellery Austria - ICT staff unit, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://www.osor.eu/eupl/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -package test.at.gv.egovernment.moa.id.auth.oauth; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.testng.Assert; -import org.testng.annotations.Test; - -import at.gv.egovernment.moa.id.protocols.oauth20.OAuth20Util; - -public class OAuth20UtilTest { - - @Test - public void validateURL() { - Assert.assertTrue(OAuth20Util.isUrl("file:/D:/dev/work/exthex/workspace/OAuthTesting/resources/keys/test_keystore.jks")); - Assert.assertTrue(OAuth20Util.isUrl("https://www.google.at/")); - Assert.assertTrue(OAuth20Util.isUrl("http://test")); - Assert.assertTrue(OAuth20Util.isUrl("http://localhost:59542/Callback")); - - - Assert.assertFalse(OAuth20Util.isUrl("http://")); - Assert.assertFalse(OAuth20Util.isUrl("123http://test")); - Assert.assertFalse(OAuth20Util.isUrl("test")); - } - - @Test - public void validateState() { - // check state for invalid characters (like < > & ; ... javascript ... to prevent xss) - - Assert.assertFalse(OAuth20Util.isValidStateValue("javascript")); - Assert.assertFalse(OAuth20Util.isValidStateValue("<Test")); - Assert.assertFalse(OAuth20Util.isValidStateValue("Test>")); - Assert.assertFalse(OAuth20Util.isValidStateValue("Tas<est")); - Assert.assertFalse(OAuth20Util.isValidStateValue("Te>st")); - Assert.assertFalse(OAuth20Util.isValidStateValue("Tes&t")); - Assert.assertFalse(OAuth20Util.isValidStateValue("Tes;t")); - Assert.assertTrue(OAuth20Util.isValidStateValue("secure_state")); - } - - - @Test - public void testExp() { - Pattern urlPattern = Pattern.compile("/oauth2/auth\\?(.*)$", Pattern.CASE_INSENSITIVE); - Matcher matcher = urlPattern.matcher("https://localhost/moa-id-auth/oauth2/auth?client_id=http://test&redirect_uri=http://localhost:59542/Callback&response_type=code&scope=profile%20eID%20eID_gov%20mandate&state=7gfnabf112ogg9segnnrfpi83q"); - System.out.println(matcher.find()); - } - -} |