且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

我如何以编程方式调用一个servlet内等认证j_security_check会做

更新时间:2023-12-03 20:05:04

我注意到,这已不再是最新的。最终的解决方案是使用Java SDK的OpenAM提供。

这是一个起点:http://openam.forgerock.org/openam-documentation/openam-doc-source/doc/dev-guide/index/chap-jdk.html

1)添加的所有附带此SDK到你的Web应用程序的jar文件。
2)改变你的servlet(或重客户端)具有下列code:

 私人无效addLoginCallbackMessage(LoginCredentialsBean loginBean,回调[]回调)
        抛出UnsupportedCallbackException在
{
    INT I = 0;
    尝试
    {
        对于(i = 0; I< callbacks.length;我++)
        {
            如果(回调[I]的instanceof TextOutputCallback并将)
            {
                handleTextOutputCallback((TextOutputCallback并将)回调[I]);
            }
            否则,如果(回调[I]的instanceof的NameCallback)
            {
                handleNameCallback(loginBean.getUsername(),(NameCallback来)回调[I]);
            }
            否则,如果(回调[I]的instanceof PasswordCallback)
            {
                handlePasswordCallback(loginBean.getPassword(),(PasswordCallback)回调[I]);
            }
            否则,如果(回调[I]的TextInputCallback的instanceof)
            {
                handleTextInputCallback((的TextInputCallback)回调[I]);
            }
            否则,如果(回调[I]的instanceof ChoiceCallback)
            {
                handleChoiceCallback((ChoiceCallback)回调[I]);
            }
        }
    }
    赶上(IOException异常E)
    {
        e.printStackTrace();
        抛出新UnsupportedCallbackException在(回调[I],e.getMessage());
    }
}私人无效handleTextOutputCallback(TextOutputCallback并将TOC)
{
    的System.out.println(得到TextOutputCallback并将);
    //根据指定类型显示信息    开关(toc.getMessageType())
    {
    案例TextOutputCallback.INFORMATION:
        的System.out.println(toc.getMessage());
        打破;
    案例TextOutputCallback.ERROR:
        的System.out.println(错误:+ toc.getMessage());
        打破;
    案例TextOutputCallback.WARNING:
        的System.out.println(警告:+ toc.getMessage());
        打破;
    默认:
        的System.out.println(不支持的消息类型:+
                toc.getMessageType());
    }
}私人无效handleNameCallback(字符串名称,NameCallback来NC)
        抛出IOException异常
{
    nc.setName(名);
}私人无效handleTextInputCallback(TIC的TextInputCallback)
        抛出IOException异常
{
    //不支持服务器端
    //提示文字输入
}私人无效handlePasswordCallback(字符串密码,PasswordCallback PC)
        抛出IOException异常
{
    //提示输入敏感信息的用户    pc.setPassword(password.toCharArray());
}私人无效handleChoiceCallback(ChoiceCallback CC)
        抛出IOException异常
{
    //不支持服务器端    //忽略所提供的设置defaultValue
    / *
    System.out.print(cc.getPrompt());    的String [] = strChoices cc.getChoices();
    对于(INT J = 0; J< strChoices.length; J ++)
    {
        System.out.print(选择[+ J +]:+ strChoices [J]);
    }
    System.out.flush();
    cc.setSelectedIndex(的Integer.parseInt((新的BufferedReader
            (新的InputStreamReader(System.in)))的readLine()))。
    * /
}
私人无效doLogin()
{
    // ...许多其他的逻辑在这里    // TODO:这一个是为OpenAM做成模块,此
    如果(_useOpenAM)
    {
        字符串ORGNAME =/;
        字符串MODULENAME =数据存储;
        字符串的区域设置=EN_US;        AuthContext LC =新AuthContext(ORGNAME);
        AuthContext.IndexType INDEXTYPE = AuthContext.IndexType.MODULE_INSTANCE;
        lc.login(INDEXTYPE,MODULENAME,环境);        布尔成功= FALSE;
        回调[]回调= NULL;        //从模块所需的信息
        而(lc.hasMoreRequirements())
        {
            回调= lc.getRequirements();
            如果(回调!= NULL)
            {
                addLoginCallbackMessage(loginBean,回调);
                lc.submitRequirements(回调);
            }
        }        如果(lc.getStatus()== AuthContext.Status.SUCCESS)
        {
            尝试
            {
                的System.out.println(登录成功);
                openAMSessionId = lc.getAuthIdentifier();
                的System.out.println(lc.getAuthIdentifier()=+ openAMSessionId);
                的System.out.println(lc.getSuccessURL()=+ lc.getSuccessURL());
                的System.out.println(。lc.getSSOToken()getAuthLevel()=+ lc.getSSOToken()getAuthLevel());
                的System.out.println(。lc.getSSOToken()getAuthType()=+ lc.getSSOToken()getAuthType());
                的System.out.println(。lc.getSSOToken()的gethostname()=+ lc.getSSOToken()的gethostname());
                的System.out.println(。lc.getSSOToken()getIdleTime()=+ lc.getSSOToken()getIdleTime());
                的System.out.println(。lc.getSSOToken()getMaxIdleTime()=+ lc.getSSOToken()getMaxIdleTime());
                的System.out.println(。lc.getSSOToken()getMaxSessionTime()=+ lc.getSSOToken()getMaxSessionTime());
                的System.out.println(。lc.getSSOToken()getTimeLeft()=+ lc.getSSOToken()getTimeLeft());
                的System.out.println(。lc.getSSOToken()getIPAddress()=+ lc.getSSOToken()getIPAddress());
                的System.out.println(。lc.getSSOToken()getTokenID()=+ lc.getSSOToken()getTokenID()的toString());
                的System.out.println(。lc.getSSOToken()getPrincipal()=+ lc.getSSOToken()getPrincipal()的toString());
            }
            赶上(例外五)
            {
                e.printStackTrace();
            }            成功= TRUE;
        }
        否则如果(lc.getStatus()== AuthContext.Status.FAILED)
        {
            的System.out.println(登录失败。);
        }
        其他
        {
            的System.out.println(未知状态:+ lc.getStatus());
        }        的System.out.println(OpenAM登录成功=+成功);
    }
}

从上面的code而言,重要的是可变openAMSessionId。这最终有会话ID的新OpenAM单点登录,你可以四处传递给所有的受保护的客户端应用程序,使用户不会被质疑登录。

我希望这有助于。

-dklotz

We have the web based form login authentication with j_securtiy_check working. We'd like to change it by programmatic login authentication. What is the proper way of having a servlet authenticate a user name and password passed to it? The servlet is obviously unprotected.

We have been experimenting with this server.xml Realm:

<Realm  className="org.apache.catalina.realm.DataSourceRealm"
    dataSourceName="UserDatabase"
    userTable="app_user" userNameCol="login_name" userCredCol="password_value"
    userRoleTable="user_perm" roleNameCol="permission_name"
    allRolesMode="authOnly" digest="MD5"
/>

The reason for this, is that we have a java webstart client that sends login information to an unprotected loginServlet. This servlet currently authenticates against a JOSSO single sign-on service but I wish to remove this and use simple tomcat7 authentication for starters. Then eventually migrate to OpenAM. If I could programmatically generate the JSSESSIONIDSSO value and stuff this into a cookie.

This is some code that I found. Is this the right way to invoke authentication?

ApplicationContextFacade acf = (ApplicationContextFacade) this.getServletContext();

Field privateField = ApplicationContextFacade.class.getDeclaredField("context");  
privateField.setAccessible(true);  
ApplicationContext appContext = (ApplicationContext) privateField.get(acf);  
Field privateField2 = ApplicationContext.class.getDeclaredField("context");  
privateField2.setAccessible(true);  
StandardContext stdContext = (StandardContext) privateField2.get(appContext);  
Realm realm = stdContext.getRealm();  

Principal principal = realm.authenticate(loginBean.getUsername(), loginBean.getPassword());  
if (principal == null)
{
   return 0;
}
GenericPrincipal genericPrincipal = (GenericPrincipal) principal;

System.out.println ("genericPrincipal=" + genericPrincipal.toString());

I noticed that this is no longer up to date. The final solution was to use the Java SDK that OpenAM provides.

This is the starting point: http://openam.forgerock.org/openam-documentation/openam-doc-source/doc/dev-guide/index/chap-jdk.html

1) add all of the jar files that come with this SDK to your web application. 2) Change your servlet (or heavy client) to have the following code:

    private void addLoginCallbackMessage(LoginCredentialsBean loginBean, Callback [] callbacks)
        throws UnsupportedCallbackException
{
    int i = 0;
    try
    {
        for (i = 0; i < callbacks.length; i++)
        {
            if (callbacks[i] instanceof TextOutputCallback)
            {
                handleTextOutputCallback((TextOutputCallback) callbacks[i]);
            }
            else if (callbacks[i] instanceof NameCallback)
            {
                handleNameCallback(loginBean.getUsername(), (NameCallback) callbacks[i]);
            }
            else if (callbacks[i] instanceof PasswordCallback)
            {
                handlePasswordCallback(loginBean.getPassword(), (PasswordCallback) callbacks[i]);
            }
            else if (callbacks[i] instanceof TextInputCallback)
            {
                handleTextInputCallback((TextInputCallback) callbacks[i]);
            }
            else if (callbacks[i] instanceof ChoiceCallback)
            {
                handleChoiceCallback((ChoiceCallback) callbacks[i]);
            }
        }
    }
    catch (IOException e)
    {
        e.printStackTrace();
        throw new UnsupportedCallbackException(callbacks[i], e.getMessage());
    }
}

private void handleTextOutputCallback(TextOutputCallback toc)
{
    System.out.println("Got TextOutputCallback");
    // display the message according to the specified type

    switch (toc.getMessageType())
    {
    case TextOutputCallback.INFORMATION:
        System.out.println(toc.getMessage());
        break;
    case TextOutputCallback.ERROR:
        System.out.println("ERROR: " + toc.getMessage());
        break;
    case TextOutputCallback.WARNING:
        System.out.println("WARNING: " + toc.getMessage());
        break;
    default:
        System.out.println("Unsupported message type: " +
                toc.getMessageType());
    }
}

private void handleNameCallback(String name, NameCallback nc)
        throws IOException
{
    nc.setName(name);
}

private void handleTextInputCallback(TextInputCallback tic)
        throws IOException
{
    // not supported for server side
    // prompt for text input
}

private void handlePasswordCallback(String password, PasswordCallback pc)
        throws IOException
{
    // prompt the user for sensitive information

    pc.setPassword(password.toCharArray());
}

private void handleChoiceCallback(ChoiceCallback cc)
        throws IOException
{
    // not supported for server side

    // ignore the provided defaultValue
    /*        
    System.out.print(cc.getPrompt());

    String [] strChoices = cc.getChoices();
    for (int j = 0; j < strChoices.length; j++)
    {
        System.out.print("choice[" + j + "] : " + strChoices[j]);
    }
    System.out.flush();
    cc.setSelectedIndex(Integer.parseInt((new BufferedReader
            (new InputStreamReader(System.in))).readLine()));
    */
}


private void doLogin ()
{
    // ... lots of other logic here

    // TODO: Make this into modules with this one being for OpenAM
    if (_useOpenAM)
    {
        String orgName = "/";
        String moduleName = "DataStore";
        String locale = "en_US";

        AuthContext lc = new AuthContext(orgName);
        AuthContext.IndexType indexType = AuthContext.IndexType.MODULE_INSTANCE;
        lc.login(indexType, moduleName, locale);

        boolean succeed = false;
        Callback [] callbacks = null;

        // get information requested from module
        while (lc.hasMoreRequirements())
        {
            callbacks = lc.getRequirements();
            if (callbacks != null)
            {
                addLoginCallbackMessage(loginBean, callbacks);
                lc.submitRequirements(callbacks);
            }
        }

        if (lc.getStatus() == AuthContext.Status.SUCCESS)
        {
            try
            {
                System.out.println("Login succeeded.");
                openAMSessionId = lc.getAuthIdentifier();
                System.out.println("lc.getAuthIdentifier()=" + openAMSessionId);
                System.out.println("lc.getSuccessURL()=" + lc.getSuccessURL());
                System.out.println("lc.getSSOToken().getAuthLevel()=" + lc.getSSOToken().getAuthLevel());
                System.out.println("lc.getSSOToken().getAuthType()=" + lc.getSSOToken().getAuthType());
                System.out.println("lc.getSSOToken().getHostName()=" + lc.getSSOToken().getHostName());
                System.out.println("lc.getSSOToken().getIdleTime()=" + lc.getSSOToken().getIdleTime());
                System.out.println("lc.getSSOToken().getMaxIdleTime()=" + lc.getSSOToken().getMaxIdleTime());
                System.out.println("lc.getSSOToken().getMaxSessionTime()=" + lc.getSSOToken().getMaxSessionTime());
                System.out.println("lc.getSSOToken().getTimeLeft()=" + lc.getSSOToken().getTimeLeft());
                System.out.println("lc.getSSOToken().getIPAddress()=" + lc.getSSOToken().getIPAddress());
                System.out.println("lc.getSSOToken().getTokenID()=" + lc.getSSOToken().getTokenID().toString());
                System.out.println("lc.getSSOToken().getPrincipal()=" + lc.getSSOToken().getPrincipal().toString());
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }

            succeed = true;
        }
        else if (lc.getStatus() == AuthContext.Status.FAILED)
        {
            System.out.println("Login failed.");
        }
        else
        {
            System.out.println("Unknown status: " + lc.getStatus());
        }

        System.out.println( "OpenAM login success=" + succeed);
    }
}

The important thing from the above code is the variable openAMSessionId . That ends up having the new OpenAM single sign on session id that you can pass around to all of your protected client applications so that the user doesn't get challenged for login.

I hope this helps.

-dklotz