ความต่อเนื่องของส่วนแรกของบทความเกี่ยวกับ JAAS มาดูกันว่าเป็นไปได้หรือไม่ที่จะใช้เฉพาะคำอธิบายประกอบสำหรับ JAAS และเราจะพบปัญหาอะไรบ้าง เราจะเรียนรู้ในส่วนนี้ว่าเครื่องมือ Servlet API ใดที่ช่วยให้เราสร้างโค้ดที่เป็นสากลมากขึ้น และขอสรุปสิ่งที่เราอ่าน
ความต่อเนื่อง
ในส่วนแรกของการทบทวนเทคโนโลยี JAAS (ดู " JAAS - เทคโนโลยีเบื้องต้น (ตอนที่ 1) ") เราได้พิจารณากรณีการใช้งานหลักสำหรับ JAAS และ Servlet API เราเห็นว่าคอนเทนเนอร์เซิร์ฟเล็ต Tomcat จัดการความปลอดภัยของเว็บแอปพลิเคชันของเราโดยใช้สถาปัตยกรรม JAAS ด้วยความรู้เกี่ยวกับ "วิธีการรับรองความถูกต้อง" และ "ขอบเขตความปลอดภัย" คอนเทนเนอร์ Tomcat เองทำให้เรามีการใช้งานกลไกการตรวจสอบสิทธิ์ที่จำเป็นและมอบ CallbackHandler ให้กับเรา เราเพิ่งใช้มันทั้งหมดในโมดูลการเข้าสู่ระบบของเรา สิ่งสำคัญเพียงอย่างเดียวที่ต้องจำคือเบราว์เซอร์จะบันทึกข้อมูลการเข้าสู่ระบบและรหัสผ่านที่ส่งผ่านการตรวจสอบสิทธิ์ขั้นพื้นฐาน ดังนั้น สำหรับการสแกนใหม่แต่ละครั้งโดยใช้ Chrome คุณสามารถกดCtrl+Shift+Nเพื่อเปิดหน้าต่างใหม่เพื่อทำงานในโหมดไม่ระบุตัวตนคำอธิบายประกอบ
การกำหนดค่าโดยใช้ XML ล้าสมัยไปนานแล้ว ดังนั้นจึงเป็นเรื่องสำคัญที่ต้องบอกว่าเริ่มต้นด้วย Servlet API เวอร์ชัน 3.0 เรามีโอกาสที่จะตั้งค่าการตั้งค่าเซิร์ฟเล็ตโดยใช้คำอธิบายประกอบ โดยไม่ต้องใช้ไฟล์ตัวอธิบายการปรับใช้ web.xml มาดูกันว่าการจัดการความปลอดภัยจะเปลี่ยนไปอย่างไรหากเราใช้คำอธิบายประกอบ และเป็นไปได้ไหมที่จะใช้วิธีการที่อธิบายไว้ข้างต้นโดยใช้คำอธิบายประกอบ? ข้อมูลจำเพาะของ Servlet API และส่วน “ คำอธิบายประกอบและความสามารถในการเสียบปลั๊ก ” จะช่วยให้เราเข้าใจคำอธิบายประกอบอีกครั้ง ส่วนนี้บอกว่าการประกาศเซิร์ฟเล็ตweb.xml
สามารถถูกแทนที่ด้วยคำอธิบายประกอบ@WebServlet
ได้ ดังนั้น servlet ของเราจะมีลักษณะดังนี้:
@WebServlet(name="app", urlPatterns = "/secret")
public class App extends HttpServlet {
ต่อไป มาดูบท " 13.3 การรักษาความปลอดภัยทางโปรแกรม " มันบอกว่าเราสามารถประกาศข้อจำกัดด้านความปลอดภัยผ่านคำอธิบายประกอบได้:
@WebServlet(name="app", urlPatterns = "/secret")
@ServletSecurity(httpMethodConstraints = {
@HttpMethodConstraint(value = "GET", rolesAllowed = "admin")
})
public class App extends HttpServlet {
ตอนนี้web.xml
เหลือเพียงบล็อกเดียวในบ้านของเรา - login-config
. ปัญหาคือมันเกิดขึ้นจนไม่มีทางที่จะแทนที่มันได้อย่างง่ายดายและง่ายดาย เนื่องจากการเชื่อมต่อที่ใกล้ชิดระหว่างการตั้งค่าความปลอดภัยของแอปพลิเคชันบนเว็บและการตั้งค่าความปลอดภัยของเว็บเซิร์ฟเวอร์ จึงไม่มีวิธีที่ง่ายและเป็นสากลในการดำเนินการนี้ แม้แต่โดยทางโปรแกรมก็ตาม นี่เป็นหนึ่งในปัญหาของการตรวจสอบสิทธิ์โดยใช้ JAAS และ Servlet API เมื่อพูดถึง block login-config
มันก็คุ้มค่าที่จะเข้าใจว่ามันเป็นคำอธิบายที่เปิดเผยของกลไกการรับรองความถูกต้องเช่น กลไกการตรวจสอบสิทธิ์ ยังไม่มีวิธีสากลง่ายๆ ที่จะแทนที่ได้ เพราะ... การประมวลผลweb.xml
เกิดขึ้นลึกภายในคอนเทนเนอร์เซิร์ฟเล็ต ตัวอย่างเช่น ใน Tomcat คุณสามารถดูแหล่งที่มาContextConfig.javaได้ ดังนั้น แม้แต่คอนเทนเนอร์เซิร์ฟเล็ต Tomcat ก็มีหลายตัวเลือกและต่างกันทั้งหมด ตัวอย่างเช่น หากเราใช้คอนเทนเนอร์เซิร์ฟเล็ต Embedded Tomcat (เช่น เราเพิ่มเว็บเซิร์ฟเวอร์จากโค้ด) คุณสามารถอ่านเกี่ยวกับตัวเลือกดังกล่าวได้ที่นี่: “ Embedded Tomcat พร้อมการรับรองความถูกต้องพื้นฐานผ่านโค้ด ” นอกจากนี้ สามารถดูตัวอย่างทั่วไปของการเพิ่ม Embedde Tomcat ได้ในคู่มือแพลตฟอร์ม Heroku PaaS: “ สร้าง Java Web Application โดยใช้ Embedded Tomcat ” หากไม่ได้ใช้ Tomcat ในโหมด Embedded ดังนั้นสำหรับ Tomcat คุณสามารถใช้แนวทางที่ใช้กันทั่วไปได้ - ตัวฟังเหตุการณ์ ใน Tomcat นี่คือ " The LifeCycle Listener Component " ในเวลาเดียวกัน สิ่งสำคัญคือต้องเข้าใจว่าเซิร์ฟเล็ตคอนเทนเนอร์ (ในกรณีของเราคือ Tomcat) อาจมีคลาสโหลดเดอร์เป็นของตัวเอง และคุณไม่สามารถรับและใช้คลาสของคุณได้ สำหรับ Tomcat คุณต้องเข้าใจ " Class Loader HOW-TO " ในคอนเทนเนอร์เซิร์ฟเล็ตอื่นที่เรียกว่า Undertow สามารถทำได้โดยใช้ " Servlet Extensions " อย่างที่คุณเห็น กลไกบางตัวมีกลไกที่ยืดหยุ่นมากกว่า ในขณะที่บางตัวไม่มี อย่างที่คุณเห็นไม่มีทางเลือกเดียว พวกเขาทั้งหมดแตกต่างกันมาก เป็นไปได้ไหมที่จะทำอะไรที่เป็นสากลด้วยเพียง Servlet API และ JAAS เท่านั้น บนอินเทอร์เน็ต คุณสามารถค้นหาข้อเสนอเพื่อใช้ Servlet Filter เพื่อดำเนินการตรวจสอบสิทธิ์โดยไม่มีการlogin-config
บล็อก ในที่สุดเรามาพิจารณาตัวเลือกนี้ สิ่งนี้จะทำให้เราสามารถทำซ้ำวิธีการทำงานของ JAAS ได้
ตัวกรองการรับรองความถูกต้อง
ดังนั้นเป้าหมายของเราคือกำจัดweb.xml
ไฟล์ให้หมด หากเรากำจัดมันออกไป น่าเสียดาย เราจะไม่สามารถใช้ข้อจำกัดด้านความปลอดภัยได้อีกต่อไป เนื่องจาก การประมวลผลสามารถเกิดขึ้นได้เร็วกว่าการใช้ตัวกรองเซิร์ฟเล็ตมาก นี่คือค่าธรรมเนียมที่คุณต้องจ่ายสำหรับ "ความสามารถรอบด้าน" ของการใช้ตัวกรอง เหล่านั้น. เราจะต้องลบคำอธิบายประกอบ@ServletSecurity
และการตรวจสอบทั้งหมดที่เราอธิบายไว้ก่อนหน้านี้ในข้อจำกัดด้านความปลอดภัยจะต้องดำเนินการโดยทางโปรแกรม อย่างที่คุณเห็น ตัวเลือกนี้ยังกำหนดข้อจำกัดที่ไม่พึงประสงค์หลายประการให้กับเราด้วย ก่อนอื่น เรามาลบคำอธิบายประกอบ@ServletSecurity
ออกจากทรัพยากรและบล็อกออกlogin-config
จากไฟล์web.xml
. ตอนนี้เราเองจะต้องดำเนินการรับรองความถูกต้องขั้นพื้นฐาน ตอนนี้เรามาเพิ่มตัวกรองของเรา:
@WebFilter("/*")
public class JaasFilter implements javax.servlet.Filter {
จนถึงตอนนี้มันดูเหมือนง่าย มาเขียนวิธีการเริ่มต้น:
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String jaas_conf = filterConfig.getServletContext().getRealPath("/WEB-INF/jaas.config");
System.getProperties().setProperty("java.security.auth.login.config",jaas_conf);
}
อย่างที่คุณเห็น ตอนนี้เราถูกบังคับให้ใช้เครื่องมือ JAAS พื้นฐานเพื่อค้นหาไฟล์กำหนดค่า jaas สิ่งนี้มีข้อเสียเปรียบอย่างมาก - หากมีหลายแอปพลิเคชัน แอปพลิเคชันหนึ่งอาจทำลายการรับรองความถูกต้องของอีกแอปพลิเคชันหนึ่งได้ วิธีการตั้งค่าไฟล์ Jaas Config โดยทั่วไปมีอธิบายโดยละเอียดในเอกสารประกอบ JAAS: " ภาคผนวก A: การตั้งค่า JAAS ในไฟล์คุณสมบัติความปลอดภัย java.security " ต่อไป เราจะอธิบายวิธีการกรองด้วยตัวเอง เริ่มต้นด้วยการรับคำขอ HTTP:
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
// Если в реквесте уже есть Principal - ничего не делаем
if (req.getUserPrincipal() != null ) {
chain.doFilter(request, response);
}
ทุกอย่างเรียบง่ายที่นี่ หากมี Principal แสดงว่าการรับรองความถูกต้องสำเร็จ ถัดไป คุณต้องอธิบายการทำงานของตัวกรองเมื่อผู้ใช้ไม่ผ่านการตรวจสอบสิทธิ์ เช่น เขายังไม่ได้รับการจดจำ ก่อนหน้านี้เราได้อธิบายวิธีการรับรองความถูกต้องพื้นฐาน BASIC เพราะ เนื่องจากตอนนี้เรากำลังเขียนตัวกรองเอง เราจึงต้องพิจารณาว่าการตรวจสอบสิทธิ์ขั้นพื้นฐานทำงานอย่างไร คุณสามารถใช้ " เอกสารเว็บ MDN: การอนุญาต HTTP " และ " การตรวจสอบสิทธิ์ HTTP ทำงานอย่างไร " จากคำอธิบายวิธีการทำงานของการตรวจสอบสิทธิ์ขั้นพื้นฐาน ชัดเจนว่าหากเซิร์ฟเวอร์ต้องการดำเนินการตรวจสอบสิทธิ์ BASIC และผู้ใช้ไม่ได้ให้ข้อมูล เซิร์ฟเวอร์จะส่งส่วนหัวพิเศษ "WWW-Authenticate" และรหัสข้อผิดพลาด 401 มาสร้าง วิธีการภายในสำหรับสิ่งนี้:
private void requestNewAuthInResponse(ServletResponse response) throws IOException {
HttpServletResponse resp = (HttpServletResponse) response;
String value = "Basic realm=\"JaasLogin\"";
resp.setHeader("WWW-Authenticate", value);
resp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
ตอนนี้ลองใช้วิธีนี้และเพิ่มdoFilter
บล็อกโค้ดต่อไปนี้ให้กับวิธีการ:
// Получаем security Header. А если его нет - запрашиваем
String secHeader = req.getHeader("authorization");
if (secHeader == null) {
requestNewAuthInResponse(response);
}
ตอนนี้เรามาเพิ่มสาขาสำหรับif
ซึ่งจะถูกดำเนินการเมื่อมีการส่งส่วนหัวแล้ว:
// Проверяем аутентификацию
else {
String authorization = secHeader.replace("Basic ", "");
Base64.Decoder decoder = java.util.Base64.getDecoder();
authorization = new String(decoder.decode(authorization));
String[] loginData = authorization.split(":");
try {
if (loginData.length == 2) {
req.login(loginData[0], loginData[1]);
chain.doFilter(request, response);
} else {
requestNewAuthInResponse(response);
}
} catch (ServletException e) {
requestNewAuthInResponse(response);
}
}
คุณสามารถเพิ่มการอนุญาตให้กับโค้ดนี้ได้ เช่น: req.isUserInRole("admin")
ดังนั้นเราจึงได้ทำการตรวจสอบสิทธิ์กับคุณโดยใช้ตัวกรอง ในด้านหนึ่ง มีโค้ดและการประมวลผลแบบแมนนวลจำนวนมาก ในทางกลับกัน มีความคล่องตัวและความเป็นอิสระของเซิร์ฟเวอร์
GO TO FULL VERSION