001// Copyright 2008-2013, 2026 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007// http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.tapestry5.internal.services;
016
017import org.apache.tapestry5.MetaDataConstants;
018import org.apache.tapestry5.SymbolConstants;
019import org.apache.tapestry5.http.Link;
020import org.apache.tapestry5.http.LinkSecurity;
021import org.apache.tapestry5.http.services.Request;
022import org.apache.tapestry5.http.services.Response;
023import org.apache.tapestry5.ioc.annotations.Symbol;
024import org.apache.tapestry5.services.ComponentEventLinkEncoder;
025import org.apache.tapestry5.services.ComponentEventRequestParameters;
026import org.apache.tapestry5.services.MetaDataLocator;
027import org.apache.tapestry5.services.PageRenderRequestParameters;
028
029import java.io.IOException;
030
031public class RequestSecurityManagerImpl implements RequestSecurityManager
032{
033    private final Request request;
034
035    private final Response response;
036
037    private final MetaDataLocator locator;
038
039    private final boolean securityEnabled;
040
041    private final ComponentEventLinkEncoder componentEventLinkEncoder;
042
043    public RequestSecurityManagerImpl(Request request, Response response,
044                                      ComponentEventLinkEncoder componentEventLinkEncoder, MetaDataLocator locator, @Symbol(SymbolConstants.SECURE_ENABLED)
045    boolean securityEnabled)
046    {
047        this.request = request;
048        this.response = response;
049        this.componentEventLinkEncoder = componentEventLinkEncoder;
050        this.locator = locator;
051        this.securityEnabled = securityEnabled;
052    }
053
054    public boolean checkForInsecureComponentEventRequest(ComponentEventRequestParameters parameters) throws IOException
055    {
056        // Both the active page and the containing page have code executing for this request,
057        // so @Secure on either must be honored.
058        if (!needsRedirect(parameters.getActivePageName())
059                && !needsRedirect(parameters.getContainingPageName()))
060        {
061            return false;
062        }
063
064        // Page is secure but request is not, so redirect.
065        // We can safely ignore the forForm parameter since secure form requests are always done from
066        // an already secured page
067
068        Link link = componentEventLinkEncoder.createComponentEventLink(parameters, false);
069
070        response.sendRedirect(link);
071
072        return true;
073    }
074
075    public boolean checkForInsecurePageRenderRequest(PageRenderRequestParameters parameters) throws IOException
076    {
077        if (!needsRedirect(parameters.getLogicalPageName()))
078            return false;
079
080        // Page is secure but request is not, so redirect.
081
082        Link link = componentEventLinkEncoder.createPageRenderLink(parameters);
083
084        response.sendRedirect(link);
085
086        return true;
087    }
088
089    private boolean needsRedirect(String pageName)
090    {
091        if (!securityEnabled)
092        {
093            return false;
094        }
095
096        // We don't (at this time) redirect from secure to insecure, just from insecure to secure.
097
098        if (request.isSecure())
099        {
100            return false;
101        }
102
103        if (!isSecure(pageName))
104        {
105            return false;
106        }
107
108        return true;
109    }
110
111    private boolean isSecure(String pageName)
112    {
113        return locator.findMeta(MetaDataConstants.SECURE_PAGE, pageName, Boolean.class);
114    }
115
116    public LinkSecurity checkPageSecurity(String pageName)
117    {
118        if (!securityEnabled)
119        {
120            return request.isSecure() ? LinkSecurity.SECURE : LinkSecurity.INSECURE;
121        }
122
123        boolean securePage = isSecure(pageName);
124
125        if (request.isSecure() == securePage)
126        {
127            return securePage ? LinkSecurity.SECURE : LinkSecurity.INSECURE;
128        }
129
130        // Return a value that will, ultimately, force an absolute URL.
131
132        return securePage ? LinkSecurity.FORCE_SECURE : LinkSecurity.FORCE_INSECURE;
133    }
134}