I am trying to create a custom authentication.
When I
I made a simple identityStore that validate every user as guest with rols AF_ADMIN and AF_USER.
CustomAuthenticationMechanism is called when login but the CredentialValidationResult from idStoreHandler have no callerGroups.
So Login-public.xhtml says I don't have AF_ADMIN role.
Am I missing anything?
CustomAuthenticationMechanism
#AutoApplySession
#LoginToContinue
#ApplicationScoped
public class CustomAuthenticationMechanism implements HttpAuthenticationMechanism {
#Inject
private IdentityStoreHandler idStoreHandler;
//#Override
public AuthenticationStatus validateRequest(HttpServletRequest request, HttpServletResponse response, HttpMessageContext httpMessageContext) throws AuthenticationException {
final String ticket = request.getParameter("ticket");
if (ticket != null) {
CredentialValidationResult result = idStoreHandler.validate(new UsernamePasswordCredential(ticket, Arrays.toString("LOGIN_PASSWORD")));
if (result.getStatus() == VALID) {
return httpMessageContext.notifyContainerAboutLogin(result);
} else {
return httpMessageContext.responseUnauthorized();
}
}
return httpMessageContext.doNothing();
}
}
login-public.xhtml
...
<h1>Public</h1>
<div class="alert alert-danger" role="alert">
#{myBean.initBean()}
<h:outputText value="inRole(AF_ADMIN): #{request.isUserInRole('AF_ADMIN')}"/><br/>
<h:outputText value="requestURL: #{request.requestURL}"/><br/>
<h:outputText value="headerNames: #{request.headerNames}"/><br/>
#{requestScope['javax.servlet.error.status_code']}
#{requestScope['javax.servlet.error.message']}<br/>
#{messages['error.inesperat']}
</div>
...
login-private.xhtml
...
<h1>Public</h1>
<div class="alert alert-danger" role="alert">
#{myBean.initBean()}
<h:outputText value="inRole(AF_ADMIN): #{request.isUserInRole('AF_ADMIN')}"/><br/>
<h:outputText value="requestURL: #{request.requestURL}"/><br/>
<h:outputText value="headerNames: #{request.headerNames}"/><br/>
#{requestScope['javax.servlet.error.status_code']}
#{requestScope['javax.servlet.error.message']}<br/>
#{messages['error.inesperat']}
</div>
...
MyLoginIdentityStory
#ApplicationScoped
public class MyLoginIdentityStore implements IdentityStore {
private static final Logger log = LoggerFactory.getLogger(LoginIBIdentityStore.class);
public static final String USER = "user";
#Inject
HttpServletRequest request;
#Inject
UsuariServiceable userSvc;
#Override
public int priority() {
return 1;
}
#Override
public Set<ValidationType> validationTypes() {
return EnumSet.of(ValidationType.VALIDATE);
}
public CredentialValidationResult validate(UsernamePasswordCredential credential) {
return new CredentialValidationResult("guest", new HashSet<>(Arrays.asList("AF_ADMIN","AF_USER")));
}
#Override
public Set<String> getCallerGroups(CredentialValidationResult validationResult) {
return IdentityStore.super.getCallerGroups(validationResult);
}
}
web.xml
...
<security-constraint>
<display-name>app_public</display-name>
<web-resource-collection>
<web-resource-name>app_public</web-resource-name>
<url-pattern>/error.xhtml</url-pattern>
<url-pattern>/login</url-pattern>
<url-pattern>/login.xhtml</url-pattern>
<url-pattern>/login-public.xhtml</url-pattern>
<url-pattern>/resources/**</url-pattern>
<url-pattern>/javax.faces.resource/*</url-pattern>
</web-resource-collection>
</security-constraint>
<security-constraint>
<display-name>app</display-name>
<web-resource-collection>
<web-resource-name>accfor_auth</web-resource-name>
<description>paginas que requieren autentificacion</description>
<url-pattern>/*</url-pattern>
<http-method>POST</http-method>
<http-method>GET</http-method>
</web-resource-collection>
<auth-constraint>
<description>Acceso a accfor</description>
<role-name>AF_ADMIN</role-name>
</auth-constraint>
</security-constraint>
...
Default validationTypes() methods return VALIDATE and PROVIDE_GROUPS.
The problem was the overridden validation types method that only returned validation and it doesn't return provide groups.
#Override
public Set<ValidationType> validationTypes() {
return EnumSet.of(ValidationType.VALIDATE, ValidationType.PROVIDE_GROUPS);
}
Related
I'm using WildFly 9.0 and IntelliJ 14 Ultimate
I can add items to the cart- and they can be viewed using a PrimeFaces data table on ViewCart.xhtml
There is a button to delete each cart item- which works.
Faces-config has been edited to return back to the ViewCart.xhtml page when the button is clicked; which seems to be the case.
The PROBEM: Cart is still showing the original list, before the item was deleted.
If I go to the product catalogue and return back to ViewCart.xhtml, the executed changes are reflected in the cart. Please can someone help?
Here is the ViewCart.xhtml page
<body>
<h:outputText value="Cart List"
style="font-family: Verdana, Helvetica, sans-serif;font-size: 18px; font-weight: 900;" />
<h:form name="ViewProductsManagedBean">
<p:dataTable id="cartTable" var="cartList"
value="#{ViewProductsManagedBean.cart}" <p:column>
<f:facet name="header">
<h:outputText value="Delete Cart Item "
style="font-family: Verdana, Helvetica, sans-serif;font-size: 16px;" />
</f:facet>
<h:commandButton action="#{ViewProductsManagedBean.removeItemFromCart(cartList.itemcode)}"> </h:commandButton>
</p:column>
</f:facet>
</p:dataTable>
</h:form>
</body>
</html>
now the managed bean:
#ManagedBean(name="ViewProductsManagedBean")
#RequestScoped
public class ViewProductsManagedBean {
public String removeItemFromCart(String itemCode){
return cartFunctions.removeItemFromCart(itemCode);
}
}
The facade that "talks" to the business logic
#Stateful
#SessionScoped
public class CartFacade {
public String removeItemFromCart(String itemCode){
return cartBean.removeItemFromCart(itemCode);
}
}
The cart been looks like follows:
#Stateful
#Local(ShoppingCartLocal.class)
#Remote(ShoppingCart.class)
#SessionScoped
public class ShoppingCartBean implements ShoppingCartLocal, ShoppingCart {
public String removeItemFromCart(String itemCode){
for(Orderitem ord:cartItems){
if(itemCode.equals(ord.getItemcode())){
cartItems.remove(ord);
System.out.println("Item removed " + itemCode);
}
}
return "ViewCart";
}
here is the full cart bean
package com.shop.cart;
/**
* Created by LalinPethiyagoda on 30/07/2015.
*/
#Stateful
#Local(ShoppingCartLocal.class)
#Remote(ShoppingCart.class)
#SessionScoped
public class ShoppingCartBean implements ShoppingCartLocal, ShoppingCart {
#PersistenceContext(unitName ="Shop")
private EntityManager cartEntityManager;
private CustomerManager customerManagerBean;
private CopyOnWriteArrayList<Orderitem> cartItems = new CopyOnWriteArrayList<>();
private List<Orderitem> cartItemsReturn = new ArrayList<>();
public void setCartItems(CopyOnWriteArrayList<Orderitem> cartItems) {
this.cartItems = cartItems;
}
private CustomerEntity customer;
public ShoppingCartBean(){}
#Override
public List<Orderitem> getCartItemsReturn() {
return cartItemsReturn;
}
public void setCartItemsReturn(List<Orderitem> cartItemsReturn) {
this.cartItemsReturn = cartItemsReturn;
}
#Override
public boolean addCartItem(ProductEntity product, int quantityPurchased){
com.shop.entity.Orderitem basketItem=new Orderitem();
Locale currentLocale = new Locale("en", "GB");
double subTotal;
// check for duplicate entry.
for (Orderitem itemsIntheCart : cartItems) {
if (itemsIntheCart.getItemcode().equals(product.getItemcode())) {
return false;
}
}
basketItem.setItemcode(product.getItemcode());
basketItem.setItemdescription(product.getItemdescription());
basketItem.setUnitprice(product.getUnitprice());
basketItem.setQuantitypurchased(quantityPurchased);
subTotal = quantityPurchased * basketItem.getUnitprice();
Double currencyAmount = new Double(subTotal);
NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance(currentLocale);
currencyFormatter.format(currencyAmount);
basketItem.setSubtotal(currencyAmount);
cartItems.add(basketItem);
return true;
}
public String removeItemFromCart(String itemCode){
for(Orderitem ord:cartItems){
if(itemCode.equals(ord.getItemcode())){
cartItems.remove(ord);
System.out.println("Item removed " + itemCode);
}
}
return "ViewCart";
}
#Override
public CopyOnWriteArrayList<Orderitem> viewCartItems(){
return this.cartItems;
}
#Override
public CopyOnWriteArrayList<Orderitem> getCartItems(){
CopyOnWriteArrayList<Orderitem> cartItemList = this.cartItems;
for(Orderitem x:cartItemList){
System.out.println(x.getItemdescription());
}
return cartItemList;
}
public CustomerEntity getCustomer() {
return customer;
}
public void setCustomer(CustomerEntity customer) {
this.customer = customer;
}
public void removeCartItem(int itemCode){
System.out.println("hello");
}
#Override
public double getTotal(){
double total=0;
for(Orderitem bItem:getCartItems()){
total = total + bItem.getSubtotal();
}
return total;
}
#PreDestroy
public void exit(){
persistCartItems();
stopSession();
}
#Override
public void persistCartItems() {
// TODO Auto-generated method stub
}
#Remove
public void stopSession(){
System.out.println("saved- all done - object detached from object pool");
}
public void assignCartToCustomer(){
customer = customerManagerBean.getVerifiedCustomer();
}
public CustomerEntity getCustomerAssociatedWithTheCart(){
return this.customer;
}
#Remove
public void remove() {
cartItems = null;
}
#Override
public void incrementQuantity() {
}
#Override
public void decrementQuantity() {
}
}
This question already has an answer here:
JSF login filter, session is null
(1 answer)
Closed 7 years ago.
I've seen many posts like mine, but none could helped me.
this is my managed bean and it's sessionScoped, if the login is ok it redirects to index page else displays error
#ManagedBean
#SessionScoped
public class LoginBean implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private static final String[] users = {"anna:qazwsx","kate:123456"};
private String username;
private String password;
private boolean loggedIn
public String doLogin() {
for (String user: users) {
String dbUsername = user.split(":")[0];
String dbPassword = user.split(":")[1];
// Successful login
if (dbUsername.equals(username) && dbPassword.equals(password)) {
loggedIn = true;
return "/tmpl/home/index.xhtml?faces-redirect=true";
}
}
// Set login ERROR
FacesMessage msg = new FacesMessage("Login error!", "ERROR MSG");
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
FacesContext.getCurrentInstance().addMessage(null, msg);
return "/login/login.xhtml";
}
public boolean isLoggedIn() {
return loggedIn;
}
}
The view, all is normal here , calls the doLogin method of managed bean
<h:form id="login-form">
<h:messages />
<h:outputText value="Nom d'utilisateur:"/>
<h:inputText value="#{loginBean.username}" id="username"/>
<br/>
<h:outputText value="Mot de passe:"/>
<h:inputSecret value="#{loginBean.password}" id="password"/>
<br/>
<h:commandButton id="button" value="Login" action="#{loginBean.doLogin}" />
<br/>
</h:form>
The filter: if the user is authenticated then the loginBean is not null and it's logged
public class LoginFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpSession session = ((HttpServletRequest) request).getSession(false);
LoginBean loginBean = (session != null) ? (LoginBean) session.getAttribute("loginBean") : null;
if (loginBean!=null)
System.out.println(loginBean.getUsername());
if (loginBean == null || !loginBean.isLoggedIn()) {
System.out.println("here agai");
String contextPath = ((HttpServletRequest)request).getContextPath();
((HttpServletResponse)response).sendRedirect(contextPath + "/login/login.xhtml");
}
chain.doFilter(request, response);
}
}
Why my managed bean (loginBean) is null?
Did you confirm that you're using the correct SessionScoped annotation?
See here:
JSF login filter, session is null
i tried with ....
<sec:logout invalidate-session="true" logout-success-url="/logoutsuccess" logouturl="/logout/>
but it is not working properly....
i want to clear everything like refresh token and access token session , cookies when user logout....
my security-servlet.xml looks like this
<!-- Protected resources -->
<sec:http create-session="never" entry-point-ref="oauthAuthenticationEntryPoint"
access-decision-manager-ref="accessDecisionManager"
xmlns="http://www.springframework.org/schema/security">
<sec:anonymous enabled="false" />
<sec:intercept-url pattern="/data/user/*"
access="IS_AUTHENTICATED_FULLY" />
<sec:logout delete-cookies="JSESSIONID" invalidate-session="true" />
<sec:custom-filter ref="resourceServerFilter"
before="PRE_AUTH_FILTER" />
<sec:access-denied-handler ref="oauthAccessDeniedHandler" />
</sec:http>
In Spring-boot application I will:
1. get OAuth2AccessToken
2. using it will delete OAuth2RefreshToken
3. and then delete itself
#Component
public class CustomLogoutSuccessHandler
extends AbstractAuthenticationTargetUrlRequestHandler
implements LogoutSuccessHandler {
private static final String BEARER_AUTHENTICATION = "Bearer ";
private static final String HEADER_AUTHORIZATION = "authorization";
#Autowired
private TokenStore tokenStore;
#Override
public void onLogoutSuccess(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Authentication authentication) throws IOException, ServletException {
String token = httpServletRequest.getHeader(HEADER_AUTHORIZATION);
if (token != null && token.startsWith(BEARER_AUTHENTICATION)) {
String accessTokenValue = token.split(" ")[1];
OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(accessTokenValue);
if (oAuth2AccessToken != null) {
OAuth2RefreshToken oAuth2RefreshToken = oAuth2AccessToken.getRefreshToken();
if (oAuth2RefreshToken != null)
tokenStore.removeRefreshToken(oAuth2RefreshToken);
tokenStore.removeAccessToken(oAuth2AccessToken);
}
}
httpServletResponse.setStatus(HttpServletResponse.SC_OK);
}
}
you can do these things into sessionDestroyedListener...almost look like this..
In this code i am updating lastLogout date ..you can do what you want
#Component("sessionDestroyedEventListener")
public class SessionDestroyedEventListener implements ApplicationListener<SessionDestroyedEvent>{
// private static Logger logger = BaseLogger.getLogger(AuthenticationEventListener.class);
#Autowired
private AuthenticationService authenticationService;
public void setAuthenticationService(AuthenticationService authenticationService) {
this.authenticationService = authenticationService;
}
/**
* Capture sessionDestroyed event and update lastLogout date after session destroyed of particular user.
*/
#Override
public void onApplicationEvent(SessionDestroyedEvent appEvent) {
SessionDestroyedEvent event = (SessionDestroyedEvent) appEvent;
Object obj = null;
UserInfo userInfo = null;
ArrayList<SecurityContext> sc = (ArrayList<SecurityContext>) event.getSecurityContexts();
Iterator<SecurityContext> itr = sc.iterator();
while (itr.hasNext()) {
obj = itr.next().getAuthentication().getPrincipal();
if (obj instanceof UserInfo) {
userInfo = (UserInfo) obj;
} else {
String userCode = (String) obj;
if (userCode == null || "".equals(userCode)) {
userCode = "UnDefinedUser";
}
userInfo = new UserInfo(userCode);
}
//authenticationService.updateLastLogoutDate(userInfo.getUsername());
}
}
}
i found a solution in stackoverflow how to code a login in JSF using HttpServletRequest.
First things first, the login.xhtml:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>Login</title>
</h:head>
<h:body>
<h3>Login here</h3>
<h:form id="loginForm">
<h:outputLabel for="username" value="Username:" />
<h:inputText value="#{loginService.userName}" id="username" requried="true" />
<br/>
<h:outputLabel for="password" value="Password:" />
<h:inputSecret value="#{loginService.password}" id="password" requried="true" />
<br/>
<h:commandButton id="button" value="Login" action="#{loginService.doLogin}" />
<br/>
<h:commandLink action="#{navigationService.redirectToIndex}" value="Home" />
<br/>
<h:messages />
<br/>
</h:form>
</h:body>
The loginService:
#Named
#SessionScoped
public class LoginService implements Serializable {
private String userName = "";
private String password = "";
#Inject
private NavigationService navigationService = null;
#Inject
private String originalURL = "";
/**
*
*/
#PostConstruct
public void init() {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
this.originalURL = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_REQUEST_URI);
if(this.originalURL == null) {
this.originalURL = externalContext.getRequestContextPath() + navigationService.toIndex();
} else {
String originalQuery = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_QUERY_STRING);
if(originalQuery != null) {
this.originalURL += "?" + originalQuery;
}
}
}
/**
*
* #return
* #throws IOException
*/
public void doLogin() throws IOException {
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext externalContext = context.getExternalContext();
HttpServletRequest request = (HttpServletRequest)externalContext.getRequest();
try {
request.login(this.userName, this.password);
User user = dao.findUserByUserName(userName);
externalContext.getSessionMap().put("user", user);
externalContext.redirect(this.originalURL);
} catch(ServletException e) {
context.addMessage(null, new FacesMessage("Unknown login"));
} catch (NoSuchUserException e) {
context.addMessage(null, new FacesMessage(e.getMessage()));
}
}
/**
*
* #return
* #throws IOException
*/
public void doLogout() throws IOException {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
externalContext.invalidateSession();
externalContext.redirect(externalContext.getRequestContextPath() + navigationService.toLogin());
}
// Getters and Setters
}
The only thing i still need to know is now:
Where can i define for which pages login is needed?
A suggested solution is: putting all the pages requiring logging under one place (folder, ex: "private_section"), and the pages that don't need it (public access) are to be put wherever in the project context except under the folder "private_section". Then you can use a simple filter to control accessing to the private region (to our folder), and through this pattern (first annotation) you can specify the region to be controlled :
// imports
#WebFilter("/private_section/*")
public class LoggingFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse res = (HttpServletResponse)response;
UserBean user = (UserBean) req.getSession().getAttribute("user");
if (user != null && user.isLoggedIn()){
chain.doFilter(request,response);
}
else res.sendRedirect(req.getContextPath()+"/index.xhtml");
}
// other overriden methods
I'm implementing a PrimeFaces picklist in a dialog. Everytime the dialog is shown the contents of the target of the picklist should change depending on a list entry shown before. Before I open the dialog I fill the target of the picklist in ProdukteBean.onEditProdukt(..) with the appropriate values. Unfortunately these target values do not show up in the target container. Here are the relevant code pieces:
list.xhtml:
<p:commandLink id="editButton" update=":dialogForm:editDialogPanel" title="Edit"
oncomplete="produktDialog.show();"
process="#this" partialSubmit="true"
action="#{produkteBean.onEditProdukt}">
<h:outputText value="Bearbeiten" />
<f:setPropertyActionListener value="#{p}" target="#{produkteBean.produkt}" />
</p:commandLink>
dialog.xhtml:
<!-- ... -->
<p:dialog id="dialog" header="Produkt-Details" widgetVar="produktDialog" appendToBody="true" showEffect="explode" hideEffect="explode" modal="true" width="500">
<p:messages id="msgs"/>
<h:form id="dialogForm">
<!-- ... -->
<p:pickList id="produkteDatenList" var="proddat" value="#{produkteBean.datenList}"
itemLabel="#{proddat.bezeichnung}" itemValue="#{proddat}"
converter="produktDatConverter"/>
<!-- ... -->
</h:form>
</p:dialog>
ProdukteBean.java:
#Named("produkteBean")
#ViewScoped // #SessionScoped // #ViewScoped
public class ProdukteBean implements Serializable {
#Inject #Transient private ProdukteService produkteService;
#Inject #Transient private DatenService datenService;
#Inject()
private ProdukteDatenBean produkteDatenBean;
private DualListModel<Dat> datenList = new DualListModel<Dat>();
private Dat dat = null;
public ProdukteBean() {
}
#PostConstruct
private void init() {
getAll();
}
private void getAll() {
logger.debug("getAll()");
getAllProdukte();
getAllDaten();
}
private void getAllDaten() {
logger.debug("getAllDaten()");
List<Dat> source = new ArrayList<Dat>();
source.addAll(datenService.list());
List<Dat> target = new ArrayList<Dat>();
if (produkt.getDaten() != null) {
logger.debug("adding " + produkt.getDaten().size() + " daten to produkt " + produkt.getName());
target.addAll(produkt.getDaten());
}
DualListModel<Dat> datenList = new DualListModel<Dat>();
datenList.setSource(source);
datenList.setTarget(target);
setDatenList(datenList);
}
public List<Produkt> getAllProdukte() {
logger.debug("getAllProdukte()");
return produkteService.list();
}
public void onEditProdukt() {
onEditProdukt(null);
}
public void onEditProdukt(ActionEvent actionEvent) {
logger.debug("onEditProdukt: " + ReflectionToStringBuilder.toString(produkt));
if (produkt != null) {
setSelectedEinheit(produkt.getEinheit());
getAllDaten();
}
FacesMessage msg = new FacesMessage("Produkt ausgewählt", produkt.getName());
FacesContext.getCurrentInstance().addMessage(null, msg);
}
/**
* #return the einheitList
*/
public List<Einheit> getEinheitList() {
if (einheitList == null) {
einheitList = produkteService.getEinheiten();
}
return einheitList;
}
}
ProduktDatConverter.java:
#FacesConverter(forClass=Dat.class,value="produktDatConverter")
#ViewScoped
public class ProduktDatConverter implements Converter {
#Inject
#Transient DatenService datenService;
#Transient
protected final Logger logger = Logger.getLogger(getClass().getName());
// gets never called (of course)
public Object getAsObject(FacesContext arg0, UIComponent arg1, String str) {
logger.debug("getAsObject(): " + str);
return null;
}
public String getAsString(FacesContext arg0, UIComponent arg1, Object object) {
if (object instanceof Dat) {
// logger.debug(" returning id " + String.valueOf(((Dat) object).getId()));
return Long.toString(((Dat) object).getId());
}
return null;
}
}
Any ideas? Many thanks in advance!
You are using #ViewScoped along CDI Managed Bean. Change it to JSF Managed Bean. Better, use CODI instead
Also see:
View Scope in CDI Weld
CDI missing #ViewScoped and #FlashScoped
I suppose it's converter + injection problem. Please, click here and refer to the BalusC answer. You can also try to replace:
#FacesConverter(forClass=Dat.class,value="produktDatConverter")
#ViewScoped
with
#ManagedBean
#RequestScoped
and call the converter like this:
converter="#{produktDatConverter}"